From 460cec99ecf0bd596164acd028d7d3db9a13a684 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Wed, 9 Dec 2020 11:07:00 +0200 Subject: [PATCH 001/249] Version set to 3.3-SNAPSHOT --- application/pom.xml | 2 +- common/actor/pom.xml | 2 +- common/dao-api/pom.xml | 2 +- common/data/pom.xml | 2 +- common/message/pom.xml | 2 +- common/pom.xml | 2 +- common/queue/pom.xml | 2 +- common/stats/pom.xml | 2 +- common/transport/coap/pom.xml | 2 +- common/transport/http/pom.xml | 2 +- common/transport/mqtt/pom.xml | 2 +- common/transport/pom.xml | 2 +- common/transport/transport-api/pom.xml | 2 +- common/util/pom.xml | 2 +- dao/pom.xml | 2 +- msa/black-box-tests/pom.xml | 2 +- msa/js-executor/package.json | 2 +- msa/js-executor/pom.xml | 2 +- msa/pom.xml | 2 +- msa/tb-node/pom.xml | 2 +- msa/tb/pom.xml | 2 +- msa/transport/coap/pom.xml | 2 +- msa/transport/http/pom.xml | 2 +- msa/transport/mqtt/pom.xml | 2 +- msa/transport/pom.xml | 2 +- msa/web-ui/package.json | 2 +- msa/web-ui/pom.xml | 2 +- netty-mqtt/pom.xml | 4 ++-- pom.xml | 2 +- rest-client/pom.xml | 2 +- rule-engine/pom.xml | 2 +- rule-engine/rule-engine-api/pom.xml | 2 +- rule-engine/rule-engine-components/pom.xml | 2 +- tools/pom.xml | 2 +- transport/coap/pom.xml | 2 +- transport/http/pom.xml | 2 +- transport/mqtt/pom.xml | 2 +- transport/pom.xml | 2 +- ui-ngx/package.json | 2 +- ui-ngx/pom.xml | 2 +- 40 files changed, 41 insertions(+), 41 deletions(-) diff --git a/application/pom.xml b/application/pom.xml index 8a12fe05bb..81986bcfe6 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT thingsboard application diff --git a/common/actor/pom.xml b/common/actor/pom.xml index 9dea3c57a3..5fe39fc810 100644 --- a/common/actor/pom.xml +++ b/common/actor/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT common org.thingsboard.common diff --git a/common/dao-api/pom.xml b/common/dao-api/pom.xml index d50399525e..a06549fa94 100644 --- a/common/dao-api/pom.xml +++ b/common/dao-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT common org.thingsboard.common diff --git a/common/data/pom.xml b/common/data/pom.xml index b2dd156acb..6fd21cd9f3 100644 --- a/common/data/pom.xml +++ b/common/data/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT common org.thingsboard.common diff --git a/common/message/pom.xml b/common/message/pom.xml index bcff40ce4d..c5a1ac03ea 100644 --- a/common/message/pom.xml +++ b/common/message/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT common org.thingsboard.common diff --git a/common/pom.xml b/common/pom.xml index 5ceae3ea57..ecda7584b3 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT thingsboard common diff --git a/common/queue/pom.xml b/common/queue/pom.xml index 54cd24f66d..14485384dd 100644 --- a/common/queue/pom.xml +++ b/common/queue/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT common org.thingsboard.common diff --git a/common/stats/pom.xml b/common/stats/pom.xml index 8cf70c7498..70fb6c48a4 100644 --- a/common/stats/pom.xml +++ b/common/stats/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT common org.thingsboard.common diff --git a/common/transport/coap/pom.xml b/common/transport/coap/pom.xml index e775286bdd..9107d2e655 100644 --- a/common/transport/coap/pom.xml +++ b/common/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/http/pom.xml b/common/transport/http/pom.xml index ab60e6d4eb..57cb835f12 100644 --- a/common/transport/http/pom.xml +++ b/common/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/mqtt/pom.xml b/common/transport/mqtt/pom.xml index 8b043b8c2e..1ff887d5e8 100644 --- a/common/transport/mqtt/pom.xml +++ b/common/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/pom.xml b/common/transport/pom.xml index 22b17989c9..b45d627444 100644 --- a/common/transport/pom.xml +++ b/common/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT common org.thingsboard.common diff --git a/common/transport/transport-api/pom.xml b/common/transport/transport-api/pom.xml index d61963053e..eccbcaa902 100644 --- a/common/transport/transport-api/pom.xml +++ b/common/transport/transport-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/util/pom.xml b/common/util/pom.xml index 474db1270e..56223281f5 100644 --- a/common/util/pom.xml +++ b/common/util/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT common org.thingsboard.common diff --git a/dao/pom.xml b/dao/pom.xml index 907ddb7150..25e867d306 100644 --- a/dao/pom.xml +++ b/dao/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT thingsboard dao diff --git a/msa/black-box-tests/pom.xml b/msa/black-box-tests/pom.xml index 339b60741f..81bfae5626 100644 --- a/msa/black-box-tests/pom.xml +++ b/msa/black-box-tests/pom.xml @@ -21,7 +21,7 @@ org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/js-executor/package.json b/msa/js-executor/package.json index af75855eaf..518a7c4de9 100644 --- a/msa/js-executor/package.json +++ b/msa/js-executor/package.json @@ -1,7 +1,7 @@ { "name": "thingsboard-js-executor", "private": true, - "version": "3.2.1", + "version": "3.3.0", "description": "ThingsBoard JavaScript Executor Microservice", "main": "server.js", "bin": "server.js", diff --git a/msa/js-executor/pom.xml b/msa/js-executor/pom.xml index 692b371275..36b4c7f6bd 100644 --- a/msa/js-executor/pom.xml +++ b/msa/js-executor/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/pom.xml b/msa/pom.xml index cfdf6ed79f..e3bd13a377 100644 --- a/msa/pom.xml +++ b/msa/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT thingsboard msa diff --git a/msa/tb-node/pom.xml b/msa/tb-node/pom.xml index ad700779a9..37a00f74dd 100644 --- a/msa/tb-node/pom.xml +++ b/msa/tb-node/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/tb/pom.xml b/msa/tb/pom.xml index d1901a3e33..2fcb2fb7b6 100644 --- a/msa/tb/pom.xml +++ b/msa/tb/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/transport/coap/pom.xml b/msa/transport/coap/pom.xml index ad09511f36..d30d71692e 100644 --- a/msa/transport/coap/pom.xml +++ b/msa/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/http/pom.xml b/msa/transport/http/pom.xml index 97196bb879..3b93dd786f 100644 --- a/msa/transport/http/pom.xml +++ b/msa/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/mqtt/pom.xml b/msa/transport/mqtt/pom.xml index 79a26aeef3..94aba6d730 100644 --- a/msa/transport/mqtt/pom.xml +++ b/msa/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/pom.xml b/msa/transport/pom.xml index 5a8b79d9d9..befee6cdea 100644 --- a/msa/transport/pom.xml +++ b/msa/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/web-ui/package.json b/msa/web-ui/package.json index 792926a86d..3897c31f5e 100644 --- a/msa/web-ui/package.json +++ b/msa/web-ui/package.json @@ -1,7 +1,7 @@ { "name": "thingsboard-web-ui", "private": true, - "version": "3.2.1", + "version": "3.3.0", "description": "ThingsBoard Web UI Microservice", "main": "server.js", "bin": "server.js", diff --git a/msa/web-ui/pom.xml b/msa/web-ui/pom.xml index 2902ea1c85..b90e344286 100644 --- a/msa/web-ui/pom.xml +++ b/msa/web-ui/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT msa org.thingsboard.msa diff --git a/netty-mqtt/pom.xml b/netty-mqtt/pom.xml index e917ce23f7..793ea83373 100644 --- a/netty-mqtt/pom.xml +++ b/netty-mqtt/pom.xml @@ -19,11 +19,11 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT thingsboard netty-mqtt - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT jar Netty MQTT Client diff --git a/pom.xml b/pom.xml index 62c16da7e2..eb49e8ed4c 100755 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT pom Thingsboard diff --git a/rest-client/pom.xml b/rest-client/pom.xml index 89f6b33a02..c47e91f68a 100644 --- a/rest-client/pom.xml +++ b/rest-client/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT thingsboard rest-client diff --git a/rule-engine/pom.xml b/rule-engine/pom.xml index 43bd3859af..222d1555be 100644 --- a/rule-engine/pom.xml +++ b/rule-engine/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT thingsboard rule-engine diff --git a/rule-engine/rule-engine-api/pom.xml b/rule-engine/rule-engine-api/pom.xml index 448b5f8760..a6691eeab8 100644 --- a/rule-engine/rule-engine-api/pom.xml +++ b/rule-engine/rule-engine-api/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT rule-engine org.thingsboard.rule-engine diff --git a/rule-engine/rule-engine-components/pom.xml b/rule-engine/rule-engine-components/pom.xml index 9fb02ec1f0..19d21c840d 100644 --- a/rule-engine/rule-engine-components/pom.xml +++ b/rule-engine/rule-engine-components/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT rule-engine org.thingsboard.rule-engine diff --git a/tools/pom.xml b/tools/pom.xml index b3fce1373f..14982ad284 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT thingsboard tools diff --git a/transport/coap/pom.xml b/transport/coap/pom.xml index 94cb8e88a9..eaf6fd6fde 100644 --- a/transport/coap/pom.xml +++ b/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/http/pom.xml b/transport/http/pom.xml index 59cfef95f0..c9733a74d3 100644 --- a/transport/http/pom.xml +++ b/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/mqtt/pom.xml b/transport/mqtt/pom.xml index b2ba041e0b..cadb102856 100644 --- a/transport/mqtt/pom.xml +++ b/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/pom.xml b/transport/pom.xml index d477fc7de2..424c94842f 100644 --- a/transport/pom.xml +++ b/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT thingsboard transport diff --git a/ui-ngx/package.json b/ui-ngx/package.json index bf05109bb6..4940ed7647 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -1,6 +1,6 @@ { "name": "thingsboard", - "version": "3.2.1", + "version": "3.3.0", "scripts": { "ng": "ng", "start": "node --max_old_space_size=8048 ./node_modules/@angular/cli/bin/ng serve --host 0.0.0.0 --open", diff --git a/ui-ngx/pom.xml b/ui-ngx/pom.xml index 0420401dbe..68cb4f86b1 100644 --- a/ui-ngx/pom.xml +++ b/ui-ngx/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT thingsboard org.thingsboard From 7667afaeae02ab3dcc6a8bb389ad6f0ab14cb441 Mon Sep 17 00:00:00 2001 From: Andrew Shvayka Date: Wed, 9 Dec 2020 17:13:11 +0200 Subject: [PATCH 002/249] Develop/lwm2m (#3826) * LwM2M - Start transport * LwM2M - Test endpoint * LwM2M - Test endpoint * LwM2M - Test add xml * LwM2M device registration * LwM2M - add get from client, add attributes and telemetry upgrade from registration client * LwM2M - add get from client, add attributes and telemetry upgrade from registration client * LwM2M implementation * LwM2M - add to service telemetry and attribute * LwM2M add to service attribute and telemetry * LwM2M - add LWM2M_CREDENTIALS to DeviceCredentialsType * LwM2M - add LWM2M_CREDENTIALS to DeviceCredentialsType * LwM2M - add transport.process * LwM2M - delete from yml tenantid, PSK -ok * LwM2M - yml del tenantId * LwM2M - add RPK * LwM2M - add connect only x509 certificate. Crate certificates in serverKeyStore.jks and clientKeyStore.jks * LwM2M - add no_sec * LwM2M - add RPK & PSK integration test with app Client * LwM2M - add RPK & PSK integration test with app Client * LwM2M - add read JKS from file * LwM2M - add read JKS from file * LwM2M - add bootstrap cert * LwM2M - add bootstrap RPK * LwM2M - add bootstrap No_sec * LwM2M - cleaned the code * LwM2M - add to 3.0 in UI credentials lwm2m * LwM2M - add to 3.0 in UI credentials lwm2m * LwM2M - add to 3.0 in UI credentials lwm2m * LwM2M - fix bug CoAP transport * LwM2M: UI - add Json to credentials * LwM2M: Back - add command "/3/0/5" - trigger client * LwM2M: fix bug Json edit dialog * LwM2M: fix bug Json edit dialog * lwm2m: fix bug Json edit dialog: add validate * lwm2m: UI add tabs * lwm2m: UI add tabs (cleaner) * lwm2m: add interface SecurityConfigModels * lwm2m: add interface SecurityConfigModels2 * lwm2m: change html * lwm2m: UI add bootstrap component * lwm2m: UI add bootstrap component with FormControl * lwm2m: UI add start Observe * lwm2m: UI - correct * lwm2m: UI - correct * lwm2m: UI - add Validator: BS RPK, X509 * lwm2m: UI - add Observe * lwm2m: UI - finish Observe * lwm2m: UI - fix bug config-service update identity * lwm2m: Bootstarp&Sewrver All config secure * lwm2m: Bootstarp&Sewrver All config secure for new Front format * lwm2m: Bootstarp&Sewrver Different config secure for new Front format * lwm2m: Add attributes Gui and Backend * lwm2m: Add attributes Gui and Backend final * lwm2m: Add telemetrys to Gui * lwm2m: Add Attribute & telemetry in Gui to instance * lwm2m: Optimize Attr/Telemetry * lwm2m: Optimize Attr/Telemetry * lwm2m: Optimize Attr/Telemetry * lwm2m: Optimize Attr/Telemetry for mobile * lwm2m: Model folder * lwm2m: Ok on AWS: NoSec, PSK, X509 bad registration - RPK * lwm2m: KeyStore start only one * lwm2m: Server observe ok * lwm2m: Server fix bug finish session without remove * lwm2m: Server add function installValue * lwm2m: Server add function getAttrTelemetry to tingsboard * lwm2m: Server add function installValue * lwm2m: Server add function update Telemetry, Attr from observe * lwm2m: Server add comments * lwm2m: Server add session listener * lwm2m: Server add onGetChangeCredentials with analyze * lwm2m: Server add onGetChangeCredentials with analyze Onserve add * lwm2m: Server: updated algorithm for analyzing dynamic changes in attributes / telemetry / observation * lwm2m: fix bug: "ngx-flowchart" compile * lwm2m: get value resource OPAQUE - byte [] to HexString * lwm2m: change path to base * lwm2m: fix bug COAP & lwm2m * Lwm2m_3_2: back: cleaner, test bootstrap-ok front: restore * Lwm2m_3_2: back: del SynchronousRegistrationListener.java * Lwm2m_3_2: front: start profile lwm2m UI * Lwm2m_3_2: front&back: add to profile lwm2m (api, getModels...) * Lwm2m_3_2: back: fix bug from commented front: add update change observe/attribute/telemetry to config json * Lwm2m_3_2: back: fix bug from commented front: add update change observe/attribute/telemetry to config json (2) * Lwm2m_3_2: back: fix bug from commented front: add update change observe/attribute/telemetry to config json (3) * Lwm2m_3_2: back: fix bug from commented front: add update change observe/attribute/telemetry to config json (4) * Lwm2m_3_2: front: add update change bootstrapConfig and save to config json * Lwm2m_3_2: update after merge master * lwm2m: fix bug proto * lwm2m: fix bug in yml keyStore.jks * lwm2m: fix bug tests * lwm2m: front: add nameThingsboard * lwm2m: fix bug Autowired lwm2mContext, caseCamel * lwm2m: back-end^ start api /lwm2m/deviceProfile/bootstrap * lwm2m: back-end: add method read models from resources * lwm2m: back-end/front: add and finish api bootstrapConfig * lwm2m: back-end: add decode profile * lwm2m: back-end: add new bin in transport api * lwm2m: add microservice lwm2m and docker lwm2m. * lwm2m: add microservice lwm2m and docker lwm2m (fix bug) * lwm2m: front: start fix bug disabled resources * lwm2m: master to lwm2m merge, front add change attribute, telemetry * lwm2m: front PR * lwm2m: front add sort keyName to Json on the start * lwm2m: front add instances * lwm2m: front add/del instances FormGrp Value * lwm2m: Merge remote-tracking branch 'origin/master' into develop/lwm2m # Conflicts: # common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java # common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/SessionMsgListener.java # ui-ngx/src/app/modules/home/components/home-components.module.ts * lwm2m: Merge remote-tracking branch 'origin/master' into develop/lwm2m * lwm2m: Front: del sort after add/del instance * lwm2m: Front: fix bug reindex FormArray after update * Lwm2m: Front fix bug add/del instans * Lwm2m: Front finish1 profile * Lwm2m: Back add profile to ModelClient * Lwm2m: Back add form profile sent thingsboard: attr/tel/observe * Lwm2m: Back -> fix bug: serverKeyStore.jks] Unable to load KeyStore files server * Lwm2m: Back -> fix bug: onRegistered an unReg * Lwm2m: Back -> add updateProfiles * Lwm2m: Back -> add updateDevice and updateProfile dynamic * Lwm2m: Back -> error if CoapCode not access * Lwm2m: Front -> clear credential * Lwm2m: Front -> credential fix bug button "save" * Lwm2m: Back -> add telemetry logLwm2m Co-authored-by: nickAS21 --- application/pom.xml | 4 + .../server/actors/device/DeviceActor.java | 2 +- .../device/DeviceActorMessageProcessor.java | 35 +- .../server/controller/BaseController.java | 4 + .../server/controller/DeviceController.java | 5 +- .../controller/DeviceLwm2mController.java | 75 ++ .../service/lwm2m/LwM2MModelsRepository.java | 256 +++++ .../device/DefaultDeviceAuthService.java | 4 +- .../DefaultTelemetrySubscriptionService.java | 1 + .../transport/DefaultTransportApiService.java | 44 + application/src/main/resources/banner.txt | 7 + .../src/main/resources/thingsboard.yml | 72 +- .../common/data/lwm2m/LwM2mInstance.java | 25 + .../server/common/data/lwm2m/LwM2mObject.java | 27 + .../common/data/lwm2m/LwM2mResource.java | 63 ++ .../data/lwm2m/ServerSecurityConfig.java | 34 + .../data/security/DeviceCredentialsType.java | 4 +- common/queue/src/main/proto/queue.proto | 46 +- .../transport/coap/CoapTransportContext.java | 1 + .../transport/coap/CoapTransportResource.java | 66 +- .../transport/coap/CoapTransportService.java | 11 +- .../coap/adaptors/JsonCoapAdaptor.java | 1 + .../transport/coap/client/DeviceEmulator.java | 21 +- .../transport/http/DeviceApiController.java | 1 + common/transport/lwm2m/pom.xml | 123 +++ ...TransportBootstrapServerConfiguration.java | 101 ++ ...2MTransportBootstrapServerInitializer.java | 70 ++ .../LwM2MTransportContextBootstrap.java | 60 ++ .../secure/LwM2MBootstrapConfig.java | 102 ++ .../secure/LwM2MBootstrapSecurityStore.java | 181 ++++ .../secure/LwM2MBootstrapServers.java | 33 + .../LwM2MInMemoryBootstrapConfigStore.java | 71 ++ .../secure/LwM2MServerBootstrap.java | 65 ++ .../LwM2MSetSecurityStoreBootstrap.java | 205 ++++ .../LwM2mDefaultBootstrapSessionManager.java | 66 ++ .../secure/LWM2MGenerationPSkRPkECC.java | 121 +++ .../lwm2m/secure/LwM2MGetSecurityInfo.java | 170 +++ .../lwm2m/secure/LwM2MSecurityMode.java | 58 + .../lwm2m/secure/LwM2mRPkCredentials.java | 84 ++ .../lwm2m/secure/ReadResultSecurityStore.java | 40 + .../lwm2m/server/LwM2MSessionMsgListener.java | 88 ++ .../server/LwM2MTransportContextServer.java | 60 ++ .../lwm2m/server/LwM2MTransportHandler.java | 333 ++++++ .../lwm2m/server/LwM2MTransportRequest.java | 335 ++++++ .../LwM2MTransportServerConfiguration.java | 102 ++ .../LwM2MTransportServerInitializer.java | 72 ++ .../lwm2m/server/LwM2MTransportService.java | 999 ++++++++++++++++++ .../lwm2m/server/LwM2mServerListener.java | 111 ++ .../transport/lwm2m/server/ResultIds.java | 38 + .../server/adaptors/LwM2MJsonAdaptor.java | 49 + .../adaptors/LwM2MTransportAdaptor.java | 27 + .../client/AttrTelemetryObserveValue.java | 47 + .../lwm2m/server/client/LwM2MClient.java | 107 ++ .../lwm2m/server/client/ModelObject.java | 41 + .../lwm2m/server/client/ResourceValue.java | 26 + .../client/ResultsAnalyzerParameters.java | 32 + .../secure/LwM2MSetSecurityStoreServer.java | 234 ++++ .../secure/LwM2mInMemorySecurityStore.java | 212 ++++ .../lwm2m/utils/LwM2mValueConverterImpl.java | 146 +++ .../transport/lwm2m/utils/TypeServer.java | 29 + .../resources/credentials/serverKeyStore.jks | Bin 0 -> 5716 bytes .../credentials/shell/lwM2M_credentials.sh | 208 ++++ .../credentials/shell/lwM2M_keygen.properties | 58 + .../lwm2m/src/main/resources/models/10241.xml | 81 ++ .../lwm2m/src/main/resources/models/10242.xml | 659 ++++++++++++ .../lwm2m/src/main/resources/models/10243.xml | 263 +++++ .../lwm2m/src/main/resources/models/10244.xml | 301 ++++++ .../lwm2m/src/main/resources/models/10245.xml | 217 ++++ .../lwm2m/src/main/resources/models/10246.xml | 108 ++ .../lwm2m/src/main/resources/models/10247.xml | 98 ++ .../lwm2m/src/main/resources/models/10248.xml | 78 ++ .../lwm2m/src/main/resources/models/10249.xml | 138 +++ .../lwm2m/src/main/resources/models/10250.xml | 70 ++ .../lwm2m/src/main/resources/models/10251.xml | 96 ++ .../lwm2m/src/main/resources/models/10252.xml | 229 ++++ .../lwm2m/src/main/resources/models/10253.xml | 72 ++ .../lwm2m/src/main/resources/models/10254.xml | 119 +++ .../lwm2m/src/main/resources/models/10255.xml | 165 +++ .../lwm2m/src/main/resources/models/10256.xml | 117 ++ .../lwm2m/src/main/resources/models/10257.xml | 275 +++++ .../lwm2m/src/main/resources/models/10258.xml | 89 ++ .../lwm2m/src/main/resources/models/10259.xml | 115 ++ .../src/main/resources/models/10260-2_0.xml | 95 ++ .../lwm2m/src/main/resources/models/10262.xml | 87 ++ .../lwm2m/src/main/resources/models/10263.xml | 90 ++ .../lwm2m/src/main/resources/models/10264.xml | 117 ++ .../lwm2m/src/main/resources/models/10265.xml | 136 +++ .../lwm2m/src/main/resources/models/10266.xml | 244 +++++ .../lwm2m/src/main/resources/models/10267.xml | 244 +++++ .../lwm2m/src/main/resources/models/10268.xml | 244 +++++ .../lwm2m/src/main/resources/models/10269.xml | 244 +++++ .../lwm2m/src/main/resources/models/10270.xml | 244 +++++ .../lwm2m/src/main/resources/models/10271.xml | 244 +++++ .../lwm2m/src/main/resources/models/10272.xml | 230 ++++ .../lwm2m/src/main/resources/models/10273.xml | 230 ++++ .../lwm2m/src/main/resources/models/10274.xml | 230 ++++ .../lwm2m/src/main/resources/models/10275.xml | 230 ++++ .../lwm2m/src/main/resources/models/10276.xml | 230 ++++ .../lwm2m/src/main/resources/models/10277.xml | 230 ++++ .../lwm2m/src/main/resources/models/10278.xml | 230 ++++ .../lwm2m/src/main/resources/models/10279.xml | 230 ++++ .../lwm2m/src/main/resources/models/10280.xml | 230 ++++ .../lwm2m/src/main/resources/models/10281.xml | 230 ++++ .../lwm2m/src/main/resources/models/10282.xml | 230 ++++ .../lwm2m/src/main/resources/models/10283.xml | 230 ++++ .../lwm2m/src/main/resources/models/10284.xml | 230 ++++ .../lwm2m/src/main/resources/models/10286.xml | 48 + .../lwm2m/src/main/resources/models/10290.xml | 198 ++++ .../lwm2m/src/main/resources/models/10291.xml | 208 ++++ .../lwm2m/src/main/resources/models/10292.xml | 208 ++++ .../lwm2m/src/main/resources/models/10299.xml | 113 ++ .../lwm2m/src/main/resources/models/10300.xml | 142 +++ .../src/main/resources/models/10308-2_0.xml | 145 +++ .../lwm2m/src/main/resources/models/10309.xml | 115 ++ .../lwm2m/src/main/resources/models/10311.xml | 164 +++ .../lwm2m/src/main/resources/models/10313.xml | 253 +++++ .../lwm2m/src/main/resources/models/10314.xml | 106 ++ .../lwm2m/src/main/resources/models/10315.xml | 129 +++ .../lwm2m/src/main/resources/models/10316.xml | 233 ++++ .../lwm2m/src/main/resources/models/10318.xml | 189 ++++ .../lwm2m/src/main/resources/models/10319.xml | 130 +++ .../lwm2m/src/main/resources/models/10320.xml | 141 +++ .../lwm2m/src/main/resources/models/10322.xml | 87 ++ .../lwm2m/src/main/resources/models/10323.xml | 90 ++ .../lwm2m/src/main/resources/models/10324.xml | 77 ++ .../lwm2m/src/main/resources/models/10326.xml | 722 +++++++++++++ .../lwm2m/src/main/resources/models/10327.xml | 68 ++ .../lwm2m/src/main/resources/models/10328.xml | 80 ++ .../lwm2m/src/main/resources/models/10329.xml | 433 ++++++++ .../lwm2m/src/main/resources/models/10330.xml | 120 +++ .../lwm2m/src/main/resources/models/10331.xml | 221 ++++ .../lwm2m/src/main/resources/models/10332.xml | 69 ++ .../lwm2m/src/main/resources/models/10333.xml | 88 ++ .../lwm2m/src/main/resources/models/10334.xml | 129 +++ .../lwm2m/src/main/resources/models/10335.xml | 97 ++ .../lwm2m/src/main/resources/models/10336.xml | 84 ++ .../lwm2m/src/main/resources/models/10337.xml | 118 +++ .../lwm2m/src/main/resources/models/10338.xml | 124 +++ .../lwm2m/src/main/resources/models/10339.xml | 114 ++ .../lwm2m/src/main/resources/models/10340.xml | 218 ++++ .../lwm2m/src/main/resources/models/10341.xml | 84 ++ .../lwm2m/src/main/resources/models/10342.xml | 84 ++ .../lwm2m/src/main/resources/models/10343.xml | 96 ++ .../lwm2m/src/main/resources/models/10344.xml | 96 ++ .../lwm2m/src/main/resources/models/10345.xml | 96 ++ .../lwm2m/src/main/resources/models/10346.xml | 96 ++ .../lwm2m/src/main/resources/models/10347.xml | 154 +++ .../lwm2m/src/main/resources/models/10348.xml | 96 ++ .../lwm2m/src/main/resources/models/10349.xml | 84 ++ .../lwm2m/src/main/resources/models/10350.xml | 116 ++ .../lwm2m/src/main/resources/models/10351.xml | 79 ++ .../lwm2m/src/main/resources/models/10352.xml | 114 ++ .../lwm2m/src/main/resources/models/10353.xml | 87 ++ .../lwm2m/src/main/resources/models/10354.xml | 217 ++++ .../lwm2m/src/main/resources/models/10355.xml | 95 ++ .../lwm2m/src/main/resources/models/10356.xml | 203 ++++ .../lwm2m/src/main/resources/models/10357.xml | 95 ++ .../lwm2m/src/main/resources/models/10358.xml | 70 ++ .../lwm2m/src/main/resources/models/10359.xml | 78 ++ .../lwm2m/src/main/resources/models/10360.xml | 70 ++ .../lwm2m/src/main/resources/models/10361.xml | 92 ++ .../lwm2m/src/main/resources/models/10362.xml | 91 ++ .../lwm2m/src/main/resources/models/10363.xml | 57 + .../lwm2m/src/main/resources/models/10364.xml | 57 + .../lwm2m/src/main/resources/models/10365.xml | 57 + .../lwm2m/src/main/resources/models/10366.xml | 59 ++ .../lwm2m/src/main/resources/models/10368.xml | 96 ++ .../lwm2m/src/main/resources/models/10369.xml | 84 ++ .../lwm2m/src/main/resources/models/2048.xml | 90 ++ .../lwm2m/src/main/resources/models/2049.xml | 59 ++ .../lwm2m/src/main/resources/models/2050.xml | 64 ++ .../lwm2m/src/main/resources/models/2051.xml | 99 ++ .../lwm2m/src/main/resources/models/2052.xml | 111 ++ .../lwm2m/src/main/resources/models/2053.xml | 165 +++ .../lwm2m/src/main/resources/models/2054.xml | 69 ++ .../lwm2m/src/main/resources/models/2055.xml | 100 ++ .../lwm2m/src/main/resources/models/2056.xml | 77 ++ .../lwm2m/src/main/resources/models/2057.xml | 92 ++ .../lwm2m/src/main/resources/models/31024.xml | 51 + .../lwm2m/src/main/resources/models/3200.xml | 129 +++ .../lwm2m/src/main/resources/models/3201.xml | 78 ++ .../lwm2m/src/main/resources/models/3202.xml | 128 +++ .../lwm2m/src/main/resources/models/3203.xml | 88 ++ .../lwm2m/src/main/resources/models/3300.xml | 138 +++ .../lwm2m/src/main/resources/models/3301.xml | 118 +++ .../lwm2m/src/main/resources/models/3302.xml | 108 ++ .../lwm2m/src/main/resources/models/3303.xml | 118 +++ .../lwm2m/src/main/resources/models/3304.xml | 118 +++ .../lwm2m/src/main/resources/models/3305.xml | 228 ++++ .../lwm2m/src/main/resources/models/3306.xml | 98 ++ .../lwm2m/src/main/resources/models/3308.xml | 88 ++ .../lwm2m/src/main/resources/models/3310.xml | 108 ++ .../lwm2m/src/main/resources/models/3311.xml | 127 +++ .../lwm2m/src/main/resources/models/3312.xml | 107 ++ .../lwm2m/src/main/resources/models/3313.xml | 107 ++ .../lwm2m/src/main/resources/models/3314.xml | 97 ++ .../lwm2m/src/main/resources/models/3315.xml | 118 +++ .../lwm2m/src/main/resources/models/3316.xml | 139 +++ .../lwm2m/src/main/resources/models/3317.xml | 139 +++ .../lwm2m/src/main/resources/models/3318.xml | 139 +++ .../lwm2m/src/main/resources/models/3319.xml | 139 +++ .../lwm2m/src/main/resources/models/3320.xml | 139 +++ .../lwm2m/src/main/resources/models/3321.xml | 139 +++ .../lwm2m/src/main/resources/models/3322.xml | 139 +++ .../lwm2m/src/main/resources/models/3323.xml | 139 +++ .../lwm2m/src/main/resources/models/3324.xml | 139 +++ .../lwm2m/src/main/resources/models/3325.xml | 139 +++ .../lwm2m/src/main/resources/models/3326.xml | 139 +++ .../lwm2m/src/main/resources/models/3327.xml | 139 +++ .../lwm2m/src/main/resources/models/3328.xml | 139 +++ .../lwm2m/src/main/resources/models/3329.xml | 139 +++ .../lwm2m/src/main/resources/models/3330.xml | 139 +++ .../lwm2m/src/main/resources/models/3331.xml | 89 ++ .../lwm2m/src/main/resources/models/3332.xml | 99 ++ .../lwm2m/src/main/resources/models/3333.xml | 78 ++ .../lwm2m/src/main/resources/models/3334.xml | 189 ++++ .../lwm2m/src/main/resources/models/3335.xml | 79 ++ .../lwm2m/src/main/resources/models/3336.xml | 119 +++ .../lwm2m/src/main/resources/models/3337.xml | 139 +++ .../lwm2m/src/main/resources/models/3338.xml | 99 ++ .../lwm2m/src/main/resources/models/3339.xml | 98 ++ .../lwm2m/src/main/resources/models/3340.xml | 159 +++ .../lwm2m/src/main/resources/models/3341.xml | 139 +++ .../lwm2m/src/main/resources/models/3342.xml | 98 ++ .../lwm2m/src/main/resources/models/3343.xml | 89 ++ .../lwm2m/src/main/resources/models/3344.xml | 99 ++ .../lwm2m/src/main/resources/models/3345.xml | 109 ++ .../lwm2m/src/main/resources/models/3346.xml | 139 +++ .../lwm2m/src/main/resources/models/3347.xml | 79 ++ .../lwm2m/src/main/resources/models/3348.xml | 69 ++ .../lwm2m/src/main/resources/models/3349.xml | 88 ++ .../lwm2m/src/main/resources/models/3350.xml | 88 ++ .../lwm2m/src/main/resources/models/3351.xml | 131 +++ .../lwm2m/src/main/resources/models/3352.xml | 124 +++ .../lwm2m/src/main/resources/models/3353.xml | 123 +++ .../lwm2m/src/main/resources/models/3354.xml | 134 +++ .../lwm2m/src/main/resources/models/3355.xml | 156 +++ .../lwm2m/src/main/resources/models/3356.xml | 120 +++ .../lwm2m/src/main/resources/models/3357.xml | 131 +++ .../lwm2m/src/main/resources/models/3358.xml | 106 ++ .../lwm2m/src/main/resources/models/3359.xml | 105 ++ .../lwm2m/src/main/resources/models/3360.xml | 128 +++ .../lwm2m/src/main/resources/models/3361.xml | 130 +++ .../lwm2m/src/main/resources/models/3362.xml | 97 ++ .../lwm2m/src/main/resources/models/3363.xml | 100 ++ .../lwm2m/src/main/resources/models/3364.xml | 97 ++ .../lwm2m/src/main/resources/models/3365.xml | 123 +++ .../lwm2m/src/main/resources/models/3366.xml | 176 +++ .../lwm2m/src/main/resources/models/3367.xml | 138 +++ .../lwm2m/src/main/resources/models/3368.xml | 100 ++ .../lwm2m/src/main/resources/models/3369.xml | 105 ++ .../lwm2m/src/main/resources/models/3370.xml | 141 +++ .../lwm2m/src/main/resources/models/3371.xml | 141 +++ .../lwm2m/src/main/resources/models/3372.xml | 115 ++ .../lwm2m/src/main/resources/models/3373.xml | 115 ++ .../lwm2m/src/main/resources/models/3374.xml | 132 +++ .../lwm2m/src/main/resources/models/3375.xml | 150 +++ .../lwm2m/src/main/resources/models/3376.xml | 97 ++ .../lwm2m/src/main/resources/models/3377.xml | 168 +++ .../lwm2m/src/main/resources/models/3378.xml | 115 ++ .../lwm2m/src/main/resources/models/3379.xml | 123 +++ .../src/main/resources/models/3380-2_0.xml | 204 ++++ .../lwm2m/src/main/resources/models/3381.xml | 110 ++ .../lwm2m/src/main/resources/models/3382.xml | 108 ++ .../lwm2m/src/main/resources/models/3383.xml | 99 ++ .../lwm2m/src/main/resources/models/3384.xml | 112 ++ .../lwm2m/src/main/resources/models/3385.xml | 110 ++ .../lwm2m/src/main/resources/models/3386.xml | 105 ++ .../LWM2M_APN_Connection_Profile-v1_0_1.xml | 324 ++++++ .../models/LWM2M_Bearer_Selection-v1_0_1.xml | 211 ++++ .../LWM2M_Cellular_Connectivity-v1_0_1.xml | 185 ++++ .../LWM2M_Connectivity_Monitoring-v1_0_2.xml | 208 ++++ .../models/LWM2M_DevCapMgmt-v1_0.xml | 174 +++ .../models/LWM2M_LOCKWIPE-v1_0_1.xml | 143 +++ .../resources/models/LWM2M_Portfolio-v1_0.xml | 126 +++ .../models/LWM2M_Software_Component-v1_0.xml | 139 +++ .../models/LWM2M_Software_Management-v1_0.xml | 279 +++++ .../models/LWM2M_WLAN_connectivity4-v1_0.xml | 572 ++++++++++ .../LwM2M_BinaryAppDataContainer-v1_0_1.xml | 147 +++ .../resources/models/LwM2M_EventLog-V1_0.xml | 145 +++ .../mqtt/session/GatewayDeviceSessionCtx.java | 1 + common/transport/pom.xml | 1 + common/transport/transport-api/pom.xml | 6 + .../common/transport/SessionMsgListener.java | 3 + .../common/transport/TransportService.java | 13 + .../lwm2m/LwM2MTransportConfigBootstrap.java | 96 ++ .../lwm2m/LwM2MTransportConfigServer.java | 241 +++++ .../DefaultTransportDeviceProfileCache.java | 47 +- .../service/DefaultTransportService.java | 23 +- docker/.env | 1 + docker/docker-compose.aws-sqs.yml | 7 +- docker/docker-compose.confluent.yml | 3 + docker/docker-compose.kafka.yml | 5 + docker/docker-compose.postgres.volumes.yml | 6 + docker/docker-compose.pubsub.yml | 5 + docker/docker-compose.rabbitmq.yml | 7 +- docker/docker-compose.service-bus.yml | 5 +- docker/docker-compose.yml | 14 + docker/docker-create-log-folders.sh | 4 +- docker/tb-lwm2m-transport.env | 6 + docker/tb-transports/lwm2m/conf/logback.xml | 50 + .../lwm2m/conf/tb-lwm2m-transport.conf | 23 + k8s/common/thingsboard.yml | 66 ++ .../server/msa/ThingsBoardDbInstaller.java | 10 +- msa/tb/README.md | 4 +- msa/tb/docker-cassandra/Dockerfile | 1 + msa/tb/docker-postgres/Dockerfile | 1 + msa/tb/docker-tb/Dockerfile | 1 + msa/transport/lwm2m/docker/Dockerfile | 33 + .../lwm2m/docker/start-tb-lwm2m-transport.sh | 33 + msa/transport/lwm2m/pom.xml | 190 ++++ msa/transport/pom.xml | 1 + pom.xml | 67 +- ...eviceCredentialsUpdateNotificationMsg.java | 8 + transport/lwm2m/pom.xml | 163 +++ transport/lwm2m/src/main/conf/logback.xml | 45 + .../src/main/conf/tb-lwm2m-transport.conf | 23 + .../main/data/credentials/serverKeyStore.jks | Bin 0 -> 5716 bytes .../lwm2m/src/main/data/models/10241.xml | 98 ++ .../lwm2m/src/main/data/models/10242.xml | 647 ++++++++++++ .../lwm2m/src/main/data/models/10243.xml | 251 +++++ .../lwm2m/src/main/data/models/10244.xml | 318 ++++++ .../lwm2m/src/main/data/models/10245.xml | 203 ++++ .../lwm2m/src/main/data/models/10246.xml | 93 ++ .../lwm2m/src/main/data/models/10247.xml | 83 ++ .../lwm2m/src/main/data/models/10248.xml | 63 ++ .../lwm2m/src/main/data/models/10249.xml | 123 +++ .../lwm2m/src/main/data/models/10250.xml | 87 ++ .../lwm2m/src/main/data/models/10251.xml | 83 ++ .../lwm2m/src/main/data/models/10252.xml | 168 +++ .../lwm2m/src/main/data/models/10253.xml | 57 + .../lwm2m/src/main/data/models/10254.xml | 123 +++ .../lwm2m/src/main/data/models/10255.xml | 104 ++ .../lwm2m/src/main/data/models/10256.xml | 134 +++ .../lwm2m/src/main/data/models/10257.xml | 292 +++++ .../lwm2m/src/main/data/models/10258.xml | 93 ++ .../lwm2m/src/main/data/models/10259.xml | 100 ++ .../lwm2m/src/main/data/models/10260-2_0.xml | 81 ++ .../lwm2m/src/main/data/models/10262.xml | 72 ++ .../lwm2m/src/main/data/models/10263.xml | 75 ++ .../lwm2m/src/main/data/models/10264.xml | 102 ++ .../lwm2m/src/main/data/models/10265.xml | 121 +++ .../lwm2m/src/main/data/models/10266.xml | 229 ++++ .../lwm2m/src/main/data/models/10267.xml | 229 ++++ .../lwm2m/src/main/data/models/10268.xml | 229 ++++ .../lwm2m/src/main/data/models/10269.xml | 229 ++++ .../lwm2m/src/main/data/models/10270.xml | 229 ++++ .../lwm2m/src/main/data/models/10271.xml | 229 ++++ .../lwm2m/src/main/data/models/10272.xml | 215 ++++ .../lwm2m/src/main/data/models/10273.xml | 215 ++++ .../lwm2m/src/main/data/models/10274.xml | 215 ++++ .../lwm2m/src/main/data/models/10275.xml | 215 ++++ .../lwm2m/src/main/data/models/10276.xml | 215 ++++ .../lwm2m/src/main/data/models/10277.xml | 215 ++++ .../lwm2m/src/main/data/models/10278.xml | 215 ++++ .../lwm2m/src/main/data/models/10279.xml | 215 ++++ .../lwm2m/src/main/data/models/10280.xml | 215 ++++ .../lwm2m/src/main/data/models/10281.xml | 215 ++++ .../lwm2m/src/main/data/models/10282.xml | 215 ++++ .../lwm2m/src/main/data/models/10283.xml | 215 ++++ .../lwm2m/src/main/data/models/10284.xml | 215 ++++ .../lwm2m/src/main/data/models/10286.xml | 65 ++ .../lwm2m/src/main/data/models/10290.xml | 183 ++++ .../lwm2m/src/main/data/models/10291.xml | 193 ++++ .../lwm2m/src/main/data/models/10292.xml | 193 ++++ .../lwm2m/src/main/data/models/10299.xml | 130 +++ .../lwm2m/src/main/data/models/10300.xml | 142 +++ .../lwm2m/src/main/data/models/10308-2_0.xml | 130 +++ .../lwm2m/src/main/data/models/10309.xml | 114 ++ .../lwm2m/src/main/data/models/10311.xml | 149 +++ .../lwm2m/src/main/data/models/10313.xml | 238 +++++ .../lwm2m/src/main/data/models/10314.xml | 113 ++ .../lwm2m/src/main/data/models/10315.xml | 115 ++ .../lwm2m/src/main/data/models/10316.xml | 219 ++++ .../lwm2m/src/main/data/models/10318.xml | 175 +++ .../lwm2m/src/main/data/models/10319.xml | 116 ++ .../lwm2m/src/main/data/models/10320.xml | 127 +++ .../lwm2m/src/main/data/models/10322.xml | 73 ++ .../lwm2m/src/main/data/models/10323.xml | 76 ++ .../lwm2m/src/main/data/models/10324.xml | 63 ++ .../lwm2m/src/main/data/models/10326.xml | 708 +++++++++++++ .../lwm2m/src/main/data/models/10327.xml | 54 + .../lwm2m/src/main/data/models/10328.xml | 66 ++ .../lwm2m/src/main/data/models/10329.xml | 419 ++++++++ .../lwm2m/src/main/data/models/10330.xml | 106 ++ .../lwm2m/src/main/data/models/10331.xml | 207 ++++ .../lwm2m/src/main/data/models/10332.xml | 55 + .../lwm2m/src/main/data/models/10333.xml | 74 ++ .../lwm2m/src/main/data/models/10334.xml | 115 ++ .../lwm2m/src/main/data/models/10335.xml | 83 ++ .../lwm2m/src/main/data/models/10336.xml | 70 ++ .../lwm2m/src/main/data/models/10337.xml | 104 ++ .../lwm2m/src/main/data/models/10338.xml | 110 ++ .../lwm2m/src/main/data/models/10339.xml | 100 ++ .../lwm2m/src/main/data/models/10340.xml | 204 ++++ .../lwm2m/src/main/data/models/10341.xml | 70 ++ .../lwm2m/src/main/data/models/10342.xml | 70 ++ .../lwm2m/src/main/data/models/10343.xml | 82 ++ .../lwm2m/src/main/data/models/10344.xml | 82 ++ .../lwm2m/src/main/data/models/10345.xml | 82 ++ .../lwm2m/src/main/data/models/10346.xml | 82 ++ .../lwm2m/src/main/data/models/10347.xml | 140 +++ .../lwm2m/src/main/data/models/10348.xml | 82 ++ .../lwm2m/src/main/data/models/10349.xml | 70 ++ .../lwm2m/src/main/data/models/10350.xml | 102 ++ .../lwm2m/src/main/data/models/10351.xml | 65 ++ .../lwm2m/src/main/data/models/10352.xml | 100 ++ .../lwm2m/src/main/data/models/10353.xml | 73 ++ .../lwm2m/src/main/data/models/10354.xml | 203 ++++ .../lwm2m/src/main/data/models/10355.xml | 81 ++ .../lwm2m/src/main/data/models/10356.xml | 189 ++++ .../lwm2m/src/main/data/models/10357.xml | 81 ++ .../lwm2m/src/main/data/models/10358.xml | 56 + .../lwm2m/src/main/data/models/10359.xml | 64 ++ .../lwm2m/src/main/data/models/10360.xml | 56 + .../lwm2m/src/main/data/models/10361.xml | 78 ++ .../lwm2m/src/main/data/models/10362.xml | 77 ++ .../lwm2m/src/main/data/models/10363.xml | 43 + .../lwm2m/src/main/data/models/10364.xml | 43 + .../lwm2m/src/main/data/models/10365.xml | 43 + .../lwm2m/src/main/data/models/10366.xml | 45 + .../lwm2m/src/main/data/models/10368.xml | 82 ++ .../lwm2m/src/main/data/models/10369.xml | 70 ++ transport/lwm2m/src/main/data/models/2048.xml | 75 ++ transport/lwm2m/src/main/data/models/2049.xml | 44 + transport/lwm2m/src/main/data/models/2050.xml | 49 + transport/lwm2m/src/main/data/models/2051.xml | 84 ++ transport/lwm2m/src/main/data/models/2052.xml | 96 ++ transport/lwm2m/src/main/data/models/2053.xml | 150 +++ transport/lwm2m/src/main/data/models/2054.xml | 54 + transport/lwm2m/src/main/data/models/2055.xml | 85 ++ transport/lwm2m/src/main/data/models/2056.xml | 62 ++ transport/lwm2m/src/main/data/models/2057.xml | 77 ++ .../lwm2m/src/main/data/models/31024.xml | 68 ++ transport/lwm2m/src/main/data/models/3200.xml | 114 ++ transport/lwm2m/src/main/data/models/3201.xml | 63 ++ transport/lwm2m/src/main/data/models/3202.xml | 113 ++ transport/lwm2m/src/main/data/models/3203.xml | 73 ++ transport/lwm2m/src/main/data/models/3300.xml | 123 +++ transport/lwm2m/src/main/data/models/3301.xml | 103 ++ transport/lwm2m/src/main/data/models/3302.xml | 93 ++ transport/lwm2m/src/main/data/models/3303.xml | 103 ++ transport/lwm2m/src/main/data/models/3304.xml | 103 ++ transport/lwm2m/src/main/data/models/3305.xml | 213 ++++ transport/lwm2m/src/main/data/models/3306.xml | 83 ++ transport/lwm2m/src/main/data/models/3308.xml | 73 ++ transport/lwm2m/src/main/data/models/3310.xml | 93 ++ transport/lwm2m/src/main/data/models/3311.xml | 113 ++ transport/lwm2m/src/main/data/models/3312.xml | 93 ++ transport/lwm2m/src/main/data/models/3313.xml | 93 ++ transport/lwm2m/src/main/data/models/3314.xml | 83 ++ transport/lwm2m/src/main/data/models/3315.xml | 103 ++ transport/lwm2m/src/main/data/models/3316.xml | 124 +++ transport/lwm2m/src/main/data/models/3317.xml | 124 +++ transport/lwm2m/src/main/data/models/3318.xml | 124 +++ transport/lwm2m/src/main/data/models/3319.xml | 124 +++ transport/lwm2m/src/main/data/models/3320.xml | 124 +++ transport/lwm2m/src/main/data/models/3321.xml | 124 +++ transport/lwm2m/src/main/data/models/3322.xml | 124 +++ transport/lwm2m/src/main/data/models/3323.xml | 124 +++ transport/lwm2m/src/main/data/models/3324.xml | 124 +++ transport/lwm2m/src/main/data/models/3325.xml | 124 +++ transport/lwm2m/src/main/data/models/3326.xml | 124 +++ transport/lwm2m/src/main/data/models/3327.xml | 124 +++ transport/lwm2m/src/main/data/models/3328.xml | 124 +++ transport/lwm2m/src/main/data/models/3329.xml | 124 +++ transport/lwm2m/src/main/data/models/3330.xml | 124 +++ transport/lwm2m/src/main/data/models/3331.xml | 74 ++ transport/lwm2m/src/main/data/models/3332.xml | 84 ++ transport/lwm2m/src/main/data/models/3333.xml | 64 ++ transport/lwm2m/src/main/data/models/3334.xml | 174 +++ transport/lwm2m/src/main/data/models/3335.xml | 64 ++ transport/lwm2m/src/main/data/models/3336.xml | 104 ++ transport/lwm2m/src/main/data/models/3337.xml | 124 +++ transport/lwm2m/src/main/data/models/3338.xml | 84 ++ transport/lwm2m/src/main/data/models/3339.xml | 83 ++ transport/lwm2m/src/main/data/models/3340.xml | 144 +++ transport/lwm2m/src/main/data/models/3341.xml | 124 +++ transport/lwm2m/src/main/data/models/3342.xml | 83 ++ transport/lwm2m/src/main/data/models/3343.xml | 74 ++ transport/lwm2m/src/main/data/models/3344.xml | 84 ++ transport/lwm2m/src/main/data/models/3345.xml | 94 ++ transport/lwm2m/src/main/data/models/3346.xml | 124 +++ transport/lwm2m/src/main/data/models/3347.xml | 64 ++ transport/lwm2m/src/main/data/models/3348.xml | 54 + transport/lwm2m/src/main/data/models/3349.xml | 73 ++ transport/lwm2m/src/main/data/models/3350.xml | 73 ++ transport/lwm2m/src/main/data/models/3351.xml | 148 +++ transport/lwm2m/src/main/data/models/3352.xml | 141 +++ transport/lwm2m/src/main/data/models/3353.xml | 140 +++ transport/lwm2m/src/main/data/models/3354.xml | 151 +++ transport/lwm2m/src/main/data/models/3355.xml | 173 +++ transport/lwm2m/src/main/data/models/3356.xml | 137 +++ transport/lwm2m/src/main/data/models/3357.xml | 148 +++ transport/lwm2m/src/main/data/models/3358.xml | 123 +++ transport/lwm2m/src/main/data/models/3359.xml | 122 +++ transport/lwm2m/src/main/data/models/3360.xml | 145 +++ transport/lwm2m/src/main/data/models/3361.xml | 147 +++ transport/lwm2m/src/main/data/models/3362.xml | 114 ++ transport/lwm2m/src/main/data/models/3363.xml | 117 ++ transport/lwm2m/src/main/data/models/3364.xml | 114 ++ transport/lwm2m/src/main/data/models/3365.xml | 140 +++ transport/lwm2m/src/main/data/models/3366.xml | 193 ++++ transport/lwm2m/src/main/data/models/3367.xml | 155 +++ transport/lwm2m/src/main/data/models/3368.xml | 117 ++ transport/lwm2m/src/main/data/models/3369.xml | 122 +++ transport/lwm2m/src/main/data/models/3370.xml | 158 +++ transport/lwm2m/src/main/data/models/3371.xml | 158 +++ transport/lwm2m/src/main/data/models/3372.xml | 132 +++ transport/lwm2m/src/main/data/models/3373.xml | 132 +++ transport/lwm2m/src/main/data/models/3374.xml | 149 +++ transport/lwm2m/src/main/data/models/3375.xml | 167 +++ transport/lwm2m/src/main/data/models/3376.xml | 114 ++ transport/lwm2m/src/main/data/models/3377.xml | 185 ++++ transport/lwm2m/src/main/data/models/3378.xml | 132 +++ transport/lwm2m/src/main/data/models/3379.xml | 140 +++ .../lwm2m/src/main/data/models/3380-2_0.xml | 221 ++++ transport/lwm2m/src/main/data/models/3381.xml | 127 +++ transport/lwm2m/src/main/data/models/3382.xml | 125 +++ transport/lwm2m/src/main/data/models/3383.xml | 116 ++ transport/lwm2m/src/main/data/models/3384.xml | 129 +++ transport/lwm2m/src/main/data/models/3385.xml | 127 +++ transport/lwm2m/src/main/data/models/3386.xml | 122 +++ .../LWM2M_APN_Connection_Profile-v1_0_1.xml | 287 +++++ .../models/LWM2M_Bearer_Selection-v1_0_1.xml | 174 +++ .../LWM2M_Cellular_Connectivity-v1_0_1.xml | 146 +++ .../LWM2M_Connectivity_Monitoring-v1_0_2.xml | 167 +++ .../data/models/LWM2M_DevCapMgmt-v1_0.xml | 130 +++ .../data/models/LWM2M_LOCKWIPE-v1_0_1.xml | 98 ++ .../main/data/models/LWM2M_Portfolio-v1_0.xml | 81 ++ .../models/LWM2M_Software_Component-v1_0.xml | 95 ++ .../models/LWM2M_Software_Management-v1_0.xml | 235 ++++ .../models/LWM2M_WLAN_connectivity4-v1_0.xml | 528 +++++++++ .../LwM2M_BinaryAppDataContainer-v1_0_1.xml | 164 +++ .../main/data/models/LwM2M_EventLog-V1_0.xml | 101 ++ .../ThingsboardLwm2mTransportApplication.java | 48 + .../lwm2m/src/main/resources/logback.xml | 26 +- .../src/main/resources/tb-lwm2m-transport.yml | 301 ++++++ transport/pom.xml | 1 + .../app/core/http/device-profile.service.ts | 15 + .../device/device-credentials.component.html | 25 + .../device/device-credentials.component.ts | 51 +- .../home/components/home-components.module.ts | 9 +- .../device-profile-dialog.component.ts | 1 - ...ile-transport-configuration.component.html | 8 +- ...ofile-transport-configuration.component.ts | 96 -- .../lwm2m-device-config-server.component.html | 120 +++ .../lwm2m-device-config-server.component.ts | 223 ++++ ...ile-transport-configuration.component.html | 140 +++ ...ofile-transport-configuration.component.ts | 541 ++++++++++ ...m-object-add-instances-list.component.html | 57 + ...m-object-add-instances-list.component.scss | 22 + ...m2m-object-add-instances-list.component.ts | 179 ++++ .../lwm2m-object-add-instances.component.html | 54 + .../lwm2m-object-add-instances.component.ts | 67 ++ .../lwm2m/lwm2m-object-list.component.html | 56 + .../lwm2m/lwm2m-object-list.component.ts | 234 ++++ ...rve-attr-telemetry-resource.component.html | 86 ++ ...serve-attr-telemetry-resource.component.ts | 156 +++ ...lwm2m-observe-attr-telemetry.component.css | 49 + ...wm2m-observe-attr-telemetry.component.html | 102 ++ .../lwm2m-observe-attr-telemetry.component.ts | 352 ++++++ .../lwm2m/lwm2m-profile-components.module.ts | 55 + .../device/lwm2m/profile-config.models.ts | 212 ++++ .../lib/gateway/gateway-form.component.html | 2 +- .../home/pages/device/device.module.ts | 7 +- .../security-config-server.component.html | 80 ++ .../lwm2m/security-config-server.component.ts | 128 +++ .../lwm2m/security-config.component.html | 160 +++ .../device/lwm2m/security-config.component.ts | 384 +++++++ .../device/lwm2m/security-config.models.ts | 154 +++ .../components/json-object-edit.component.ts | 16 +- ui-ngx/src/app/shared/models/device.models.ts | 26 +- .../assets/locale/locale.constant-en_US.json | 77 +- 574 files changed, 70717 insertions(+), 204 deletions(-) create mode 100644 application/src/main/java/org/thingsboard/server/controller/DeviceLwm2mController.java create mode 100644 application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MModelsRepository.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mInstance.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mObject.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mResource.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/ServerSecurityConfig.java create mode 100644 common/transport/lwm2m/pom.xml create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerConfiguration.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerInitializer.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportContextBootstrap.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapServers.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MInMemoryBootstrapConfigStore.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MServerBootstrap.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MSetSecurityStoreBootstrap.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LWM2MGenerationPSkRPkECC.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2MGetSecurityInfo.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2MSecurityMode.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mRPkCredentials.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/ReadResultSecurityStore.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MSessionMsgListener.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportContextServer.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportHandler.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerConfiguration.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerInitializer.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ResultIds.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/adaptors/LwM2MJsonAdaptor.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/adaptors/LwM2MTransportAdaptor.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/AttrTelemetryObserveValue.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ModelObject.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResourceValue.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResultsAnalyzerParameters.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2MSetSecurityStoreServer.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/TypeServer.java create mode 100644 common/transport/lwm2m/src/main/resources/credentials/serverKeyStore.jks create mode 100755 common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh create mode 100644 common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_keygen.properties create mode 100644 common/transport/lwm2m/src/main/resources/models/10241.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10242.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10243.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10244.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10245.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10246.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10247.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10248.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10249.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10250.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10251.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10252.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10253.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10254.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10255.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10256.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10257.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10258.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10259.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10260-2_0.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10262.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10263.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10264.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10265.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10266.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10267.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10268.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10269.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10270.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10271.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10272.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10273.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10274.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10275.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10276.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10277.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10278.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10279.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10280.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10281.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10282.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10283.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10284.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10286.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10290.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10291.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10292.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10299.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10300.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10308-2_0.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10309.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10311.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10313.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10314.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10315.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10316.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10318.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10319.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10320.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10322.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10323.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10324.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10326.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10327.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10328.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10329.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10330.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10331.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10332.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10333.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10334.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10335.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10336.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10337.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10338.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10339.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10340.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10341.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10342.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10343.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10344.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10345.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10346.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10347.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10348.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10349.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10350.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10351.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10352.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10353.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10354.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10355.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10356.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10357.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10358.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10359.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10360.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10361.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10362.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10363.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10364.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10365.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10366.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10368.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/10369.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/2048.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/2049.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/2050.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/2051.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/2052.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/2053.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/2054.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/2055.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/2056.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/2057.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/31024.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3200.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3201.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3202.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3203.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3300.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3301.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3302.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3303.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3304.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3305.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3306.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3308.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3310.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3311.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3312.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3313.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3314.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3315.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3316.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3317.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3318.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3319.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3320.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3321.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3322.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3323.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3324.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3325.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3326.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3327.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3328.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3329.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3330.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3331.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3332.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3333.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3334.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3335.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3336.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3337.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3338.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3339.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3340.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3341.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3342.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3343.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3344.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3345.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3346.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3347.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3348.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3349.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3350.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3351.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3352.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3353.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3354.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3355.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3356.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3357.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3358.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3359.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3360.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3361.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3362.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3363.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3364.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3365.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3366.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3367.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3368.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3369.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3370.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3371.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3372.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3373.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3374.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3375.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3376.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3377.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3378.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3379.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3380-2_0.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3381.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3382.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3383.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3384.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3385.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/3386.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/LWM2M_APN_Connection_Profile-v1_0_1.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/LWM2M_Bearer_Selection-v1_0_1.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/LWM2M_Cellular_Connectivity-v1_0_1.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/LWM2M_Connectivity_Monitoring-v1_0_2.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/LWM2M_DevCapMgmt-v1_0.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/LWM2M_LOCKWIPE-v1_0_1.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/LWM2M_Portfolio-v1_0.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/LWM2M_Software_Component-v1_0.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/LWM2M_Software_Management-v1_0.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/LWM2M_WLAN_connectivity4-v1_0.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/LwM2M_BinaryAppDataContainer-v1_0_1.xml create mode 100644 common/transport/lwm2m/src/main/resources/models/LwM2M_EventLog-V1_0.xml create mode 100644 common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigBootstrap.java create mode 100644 common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigServer.java create mode 100644 docker/tb-lwm2m-transport.env create mode 100644 docker/tb-transports/lwm2m/conf/logback.xml create mode 100644 docker/tb-transports/lwm2m/conf/tb-lwm2m-transport.conf create mode 100644 msa/transport/lwm2m/docker/Dockerfile create mode 100755 msa/transport/lwm2m/docker/start-tb-lwm2m-transport.sh create mode 100644 msa/transport/lwm2m/pom.xml create mode 100644 transport/lwm2m/pom.xml create mode 100644 transport/lwm2m/src/main/conf/logback.xml create mode 100644 transport/lwm2m/src/main/conf/tb-lwm2m-transport.conf create mode 100644 transport/lwm2m/src/main/data/credentials/serverKeyStore.jks create mode 100644 transport/lwm2m/src/main/data/models/10241.xml create mode 100644 transport/lwm2m/src/main/data/models/10242.xml create mode 100644 transport/lwm2m/src/main/data/models/10243.xml create mode 100644 transport/lwm2m/src/main/data/models/10244.xml create mode 100644 transport/lwm2m/src/main/data/models/10245.xml create mode 100644 transport/lwm2m/src/main/data/models/10246.xml create mode 100644 transport/lwm2m/src/main/data/models/10247.xml create mode 100644 transport/lwm2m/src/main/data/models/10248.xml create mode 100644 transport/lwm2m/src/main/data/models/10249.xml create mode 100644 transport/lwm2m/src/main/data/models/10250.xml create mode 100644 transport/lwm2m/src/main/data/models/10251.xml create mode 100644 transport/lwm2m/src/main/data/models/10252.xml create mode 100644 transport/lwm2m/src/main/data/models/10253.xml create mode 100644 transport/lwm2m/src/main/data/models/10254.xml create mode 100644 transport/lwm2m/src/main/data/models/10255.xml create mode 100644 transport/lwm2m/src/main/data/models/10256.xml create mode 100644 transport/lwm2m/src/main/data/models/10257.xml create mode 100644 transport/lwm2m/src/main/data/models/10258.xml create mode 100644 transport/lwm2m/src/main/data/models/10259.xml create mode 100644 transport/lwm2m/src/main/data/models/10260-2_0.xml create mode 100644 transport/lwm2m/src/main/data/models/10262.xml create mode 100644 transport/lwm2m/src/main/data/models/10263.xml create mode 100644 transport/lwm2m/src/main/data/models/10264.xml create mode 100644 transport/lwm2m/src/main/data/models/10265.xml create mode 100644 transport/lwm2m/src/main/data/models/10266.xml create mode 100644 transport/lwm2m/src/main/data/models/10267.xml create mode 100644 transport/lwm2m/src/main/data/models/10268.xml create mode 100644 transport/lwm2m/src/main/data/models/10269.xml create mode 100644 transport/lwm2m/src/main/data/models/10270.xml create mode 100644 transport/lwm2m/src/main/data/models/10271.xml create mode 100644 transport/lwm2m/src/main/data/models/10272.xml create mode 100644 transport/lwm2m/src/main/data/models/10273.xml create mode 100644 transport/lwm2m/src/main/data/models/10274.xml create mode 100644 transport/lwm2m/src/main/data/models/10275.xml create mode 100644 transport/lwm2m/src/main/data/models/10276.xml create mode 100644 transport/lwm2m/src/main/data/models/10277.xml create mode 100644 transport/lwm2m/src/main/data/models/10278.xml create mode 100644 transport/lwm2m/src/main/data/models/10279.xml create mode 100644 transport/lwm2m/src/main/data/models/10280.xml create mode 100644 transport/lwm2m/src/main/data/models/10281.xml create mode 100644 transport/lwm2m/src/main/data/models/10282.xml create mode 100644 transport/lwm2m/src/main/data/models/10283.xml create mode 100644 transport/lwm2m/src/main/data/models/10284.xml create mode 100644 transport/lwm2m/src/main/data/models/10286.xml create mode 100644 transport/lwm2m/src/main/data/models/10290.xml create mode 100644 transport/lwm2m/src/main/data/models/10291.xml create mode 100644 transport/lwm2m/src/main/data/models/10292.xml create mode 100644 transport/lwm2m/src/main/data/models/10299.xml create mode 100644 transport/lwm2m/src/main/data/models/10300.xml create mode 100644 transport/lwm2m/src/main/data/models/10308-2_0.xml create mode 100644 transport/lwm2m/src/main/data/models/10309.xml create mode 100644 transport/lwm2m/src/main/data/models/10311.xml create mode 100644 transport/lwm2m/src/main/data/models/10313.xml create mode 100644 transport/lwm2m/src/main/data/models/10314.xml create mode 100644 transport/lwm2m/src/main/data/models/10315.xml create mode 100644 transport/lwm2m/src/main/data/models/10316.xml create mode 100644 transport/lwm2m/src/main/data/models/10318.xml create mode 100644 transport/lwm2m/src/main/data/models/10319.xml create mode 100644 transport/lwm2m/src/main/data/models/10320.xml create mode 100644 transport/lwm2m/src/main/data/models/10322.xml create mode 100644 transport/lwm2m/src/main/data/models/10323.xml create mode 100644 transport/lwm2m/src/main/data/models/10324.xml create mode 100644 transport/lwm2m/src/main/data/models/10326.xml create mode 100644 transport/lwm2m/src/main/data/models/10327.xml create mode 100644 transport/lwm2m/src/main/data/models/10328.xml create mode 100644 transport/lwm2m/src/main/data/models/10329.xml create mode 100644 transport/lwm2m/src/main/data/models/10330.xml create mode 100644 transport/lwm2m/src/main/data/models/10331.xml create mode 100644 transport/lwm2m/src/main/data/models/10332.xml create mode 100644 transport/lwm2m/src/main/data/models/10333.xml create mode 100644 transport/lwm2m/src/main/data/models/10334.xml create mode 100644 transport/lwm2m/src/main/data/models/10335.xml create mode 100644 transport/lwm2m/src/main/data/models/10336.xml create mode 100644 transport/lwm2m/src/main/data/models/10337.xml create mode 100644 transport/lwm2m/src/main/data/models/10338.xml create mode 100644 transport/lwm2m/src/main/data/models/10339.xml create mode 100644 transport/lwm2m/src/main/data/models/10340.xml create mode 100644 transport/lwm2m/src/main/data/models/10341.xml create mode 100644 transport/lwm2m/src/main/data/models/10342.xml create mode 100644 transport/lwm2m/src/main/data/models/10343.xml create mode 100644 transport/lwm2m/src/main/data/models/10344.xml create mode 100644 transport/lwm2m/src/main/data/models/10345.xml create mode 100644 transport/lwm2m/src/main/data/models/10346.xml create mode 100644 transport/lwm2m/src/main/data/models/10347.xml create mode 100644 transport/lwm2m/src/main/data/models/10348.xml create mode 100644 transport/lwm2m/src/main/data/models/10349.xml create mode 100644 transport/lwm2m/src/main/data/models/10350.xml create mode 100644 transport/lwm2m/src/main/data/models/10351.xml create mode 100644 transport/lwm2m/src/main/data/models/10352.xml create mode 100644 transport/lwm2m/src/main/data/models/10353.xml create mode 100644 transport/lwm2m/src/main/data/models/10354.xml create mode 100644 transport/lwm2m/src/main/data/models/10355.xml create mode 100644 transport/lwm2m/src/main/data/models/10356.xml create mode 100644 transport/lwm2m/src/main/data/models/10357.xml create mode 100644 transport/lwm2m/src/main/data/models/10358.xml create mode 100644 transport/lwm2m/src/main/data/models/10359.xml create mode 100644 transport/lwm2m/src/main/data/models/10360.xml create mode 100644 transport/lwm2m/src/main/data/models/10361.xml create mode 100644 transport/lwm2m/src/main/data/models/10362.xml create mode 100644 transport/lwm2m/src/main/data/models/10363.xml create mode 100644 transport/lwm2m/src/main/data/models/10364.xml create mode 100644 transport/lwm2m/src/main/data/models/10365.xml create mode 100644 transport/lwm2m/src/main/data/models/10366.xml create mode 100644 transport/lwm2m/src/main/data/models/10368.xml create mode 100644 transport/lwm2m/src/main/data/models/10369.xml create mode 100644 transport/lwm2m/src/main/data/models/2048.xml create mode 100644 transport/lwm2m/src/main/data/models/2049.xml create mode 100644 transport/lwm2m/src/main/data/models/2050.xml create mode 100644 transport/lwm2m/src/main/data/models/2051.xml create mode 100644 transport/lwm2m/src/main/data/models/2052.xml create mode 100644 transport/lwm2m/src/main/data/models/2053.xml create mode 100644 transport/lwm2m/src/main/data/models/2054.xml create mode 100644 transport/lwm2m/src/main/data/models/2055.xml create mode 100644 transport/lwm2m/src/main/data/models/2056.xml create mode 100644 transport/lwm2m/src/main/data/models/2057.xml create mode 100644 transport/lwm2m/src/main/data/models/31024.xml create mode 100644 transport/lwm2m/src/main/data/models/3200.xml create mode 100644 transport/lwm2m/src/main/data/models/3201.xml create mode 100644 transport/lwm2m/src/main/data/models/3202.xml create mode 100644 transport/lwm2m/src/main/data/models/3203.xml create mode 100644 transport/lwm2m/src/main/data/models/3300.xml create mode 100644 transport/lwm2m/src/main/data/models/3301.xml create mode 100644 transport/lwm2m/src/main/data/models/3302.xml create mode 100644 transport/lwm2m/src/main/data/models/3303.xml create mode 100644 transport/lwm2m/src/main/data/models/3304.xml create mode 100644 transport/lwm2m/src/main/data/models/3305.xml create mode 100644 transport/lwm2m/src/main/data/models/3306.xml create mode 100644 transport/lwm2m/src/main/data/models/3308.xml create mode 100644 transport/lwm2m/src/main/data/models/3310.xml create mode 100644 transport/lwm2m/src/main/data/models/3311.xml create mode 100644 transport/lwm2m/src/main/data/models/3312.xml create mode 100644 transport/lwm2m/src/main/data/models/3313.xml create mode 100644 transport/lwm2m/src/main/data/models/3314.xml create mode 100644 transport/lwm2m/src/main/data/models/3315.xml create mode 100644 transport/lwm2m/src/main/data/models/3316.xml create mode 100644 transport/lwm2m/src/main/data/models/3317.xml create mode 100644 transport/lwm2m/src/main/data/models/3318.xml create mode 100644 transport/lwm2m/src/main/data/models/3319.xml create mode 100644 transport/lwm2m/src/main/data/models/3320.xml create mode 100644 transport/lwm2m/src/main/data/models/3321.xml create mode 100644 transport/lwm2m/src/main/data/models/3322.xml create mode 100644 transport/lwm2m/src/main/data/models/3323.xml create mode 100644 transport/lwm2m/src/main/data/models/3324.xml create mode 100644 transport/lwm2m/src/main/data/models/3325.xml create mode 100644 transport/lwm2m/src/main/data/models/3326.xml create mode 100644 transport/lwm2m/src/main/data/models/3327.xml create mode 100644 transport/lwm2m/src/main/data/models/3328.xml create mode 100644 transport/lwm2m/src/main/data/models/3329.xml create mode 100644 transport/lwm2m/src/main/data/models/3330.xml create mode 100644 transport/lwm2m/src/main/data/models/3331.xml create mode 100644 transport/lwm2m/src/main/data/models/3332.xml create mode 100644 transport/lwm2m/src/main/data/models/3333.xml create mode 100644 transport/lwm2m/src/main/data/models/3334.xml create mode 100644 transport/lwm2m/src/main/data/models/3335.xml create mode 100644 transport/lwm2m/src/main/data/models/3336.xml create mode 100644 transport/lwm2m/src/main/data/models/3337.xml create mode 100644 transport/lwm2m/src/main/data/models/3338.xml create mode 100644 transport/lwm2m/src/main/data/models/3339.xml create mode 100644 transport/lwm2m/src/main/data/models/3340.xml create mode 100644 transport/lwm2m/src/main/data/models/3341.xml create mode 100644 transport/lwm2m/src/main/data/models/3342.xml create mode 100644 transport/lwm2m/src/main/data/models/3343.xml create mode 100644 transport/lwm2m/src/main/data/models/3344.xml create mode 100644 transport/lwm2m/src/main/data/models/3345.xml create mode 100644 transport/lwm2m/src/main/data/models/3346.xml create mode 100644 transport/lwm2m/src/main/data/models/3347.xml create mode 100644 transport/lwm2m/src/main/data/models/3348.xml create mode 100644 transport/lwm2m/src/main/data/models/3349.xml create mode 100644 transport/lwm2m/src/main/data/models/3350.xml create mode 100644 transport/lwm2m/src/main/data/models/3351.xml create mode 100644 transport/lwm2m/src/main/data/models/3352.xml create mode 100644 transport/lwm2m/src/main/data/models/3353.xml create mode 100644 transport/lwm2m/src/main/data/models/3354.xml create mode 100644 transport/lwm2m/src/main/data/models/3355.xml create mode 100644 transport/lwm2m/src/main/data/models/3356.xml create mode 100644 transport/lwm2m/src/main/data/models/3357.xml create mode 100644 transport/lwm2m/src/main/data/models/3358.xml create mode 100644 transport/lwm2m/src/main/data/models/3359.xml create mode 100644 transport/lwm2m/src/main/data/models/3360.xml create mode 100644 transport/lwm2m/src/main/data/models/3361.xml create mode 100644 transport/lwm2m/src/main/data/models/3362.xml create mode 100644 transport/lwm2m/src/main/data/models/3363.xml create mode 100644 transport/lwm2m/src/main/data/models/3364.xml create mode 100644 transport/lwm2m/src/main/data/models/3365.xml create mode 100644 transport/lwm2m/src/main/data/models/3366.xml create mode 100644 transport/lwm2m/src/main/data/models/3367.xml create mode 100644 transport/lwm2m/src/main/data/models/3368.xml create mode 100644 transport/lwm2m/src/main/data/models/3369.xml create mode 100644 transport/lwm2m/src/main/data/models/3370.xml create mode 100644 transport/lwm2m/src/main/data/models/3371.xml create mode 100644 transport/lwm2m/src/main/data/models/3372.xml create mode 100644 transport/lwm2m/src/main/data/models/3373.xml create mode 100644 transport/lwm2m/src/main/data/models/3374.xml create mode 100644 transport/lwm2m/src/main/data/models/3375.xml create mode 100644 transport/lwm2m/src/main/data/models/3376.xml create mode 100644 transport/lwm2m/src/main/data/models/3377.xml create mode 100644 transport/lwm2m/src/main/data/models/3378.xml create mode 100644 transport/lwm2m/src/main/data/models/3379.xml create mode 100644 transport/lwm2m/src/main/data/models/3380-2_0.xml create mode 100644 transport/lwm2m/src/main/data/models/3381.xml create mode 100644 transport/lwm2m/src/main/data/models/3382.xml create mode 100644 transport/lwm2m/src/main/data/models/3383.xml create mode 100644 transport/lwm2m/src/main/data/models/3384.xml create mode 100644 transport/lwm2m/src/main/data/models/3385.xml create mode 100644 transport/lwm2m/src/main/data/models/3386.xml create mode 100644 transport/lwm2m/src/main/data/models/LWM2M_APN_Connection_Profile-v1_0_1.xml create mode 100644 transport/lwm2m/src/main/data/models/LWM2M_Bearer_Selection-v1_0_1.xml create mode 100644 transport/lwm2m/src/main/data/models/LWM2M_Cellular_Connectivity-v1_0_1.xml create mode 100644 transport/lwm2m/src/main/data/models/LWM2M_Connectivity_Monitoring-v1_0_2.xml create mode 100644 transport/lwm2m/src/main/data/models/LWM2M_DevCapMgmt-v1_0.xml create mode 100644 transport/lwm2m/src/main/data/models/LWM2M_LOCKWIPE-v1_0_1.xml create mode 100644 transport/lwm2m/src/main/data/models/LWM2M_Portfolio-v1_0.xml create mode 100644 transport/lwm2m/src/main/data/models/LWM2M_Software_Component-v1_0.xml create mode 100644 transport/lwm2m/src/main/data/models/LWM2M_Software_Management-v1_0.xml create mode 100644 transport/lwm2m/src/main/data/models/LWM2M_WLAN_connectivity4-v1_0.xml create mode 100644 transport/lwm2m/src/main/data/models/LwM2M_BinaryAppDataContainer-v1_0_1.xml create mode 100644 transport/lwm2m/src/main/data/models/LwM2M_EventLog-V1_0.xml create mode 100644 transport/lwm2m/src/main/java/org/thingsboard/server/lwm2m/ThingsboardLwm2mTransportApplication.java rename ui-ngx/src/app/modules/home/components/profile/device/lwm2m-device-profile-transport-configuration.component.html => transport/lwm2m/src/main/resources/logback.xml (52%) create mode 100644 transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml delete mode 100644 ui-ngx/src/app/modules/home/components/profile/device/lwm2m-device-profile-transport-configuration.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html create mode 100644 ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html create mode 100644 ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.html create mode 100644 ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.html create mode 100644 ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.html create mode 100644 ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resource.component.html create mode 100644 ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resource.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.css create mode 100644 ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.html create mode 100644 ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-components.module.ts create mode 100644 ui-ngx/src/app/modules/home/components/profile/device/lwm2m/profile-config.models.ts create mode 100644 ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config-server.component.html create mode 100644 ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config-server.component.ts create mode 100644 ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config.component.html create mode 100644 ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config.component.ts create mode 100644 ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config.models.ts diff --git a/application/pom.xml b/application/pom.xml index 81986bcfe6..34d5e3d973 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -85,6 +85,10 @@ org.thingsboard.common.transport coap + + org.thingsboard.common.transport + lwm2m + org.thingsboard dao diff --git a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActor.java b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActor.java index feecef859f..9299929276 100644 --- a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActor.java +++ b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActor.java @@ -62,7 +62,7 @@ public class DeviceActor extends ContextAwareActor { processor.processAttributesUpdate(ctx, (DeviceAttributesEventNotificationMsg) msg); break; case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG: - processor.processCredentialsUpdate(); + processor.processCredentialsUpdate(msg); break; case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG: processor.processNameOrTypeUpdate((DeviceNameOrTypeUpdateMsg) msg); diff --git a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java index cf4aa3edda..605e601368 100644 --- a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java @@ -24,6 +24,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; import org.thingsboard.rule.engine.api.RpcError; import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg; +import org.thingsboard.rule.engine.api.msg.DeviceCredentialsUpdateNotificationMsg; import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg; import org.thingsboard.server.actors.ActorSystemContext; import org.thingsboard.server.actors.TbActorCtx; @@ -36,6 +37,9 @@ import org.thingsboard.server.common.data.kv.AttributeKey; import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody; +import org.thingsboard.server.common.data.security.DeviceCredentials; +import org.thingsboard.server.common.data.security.DeviceCredentialsType; +import org.thingsboard.server.common.msg.TbActorMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.queue.TbCallback; import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; @@ -61,6 +65,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcResponseM import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcResponseMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToTransportUpdateCredentialsProto; import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto; import org.thingsboard.server.service.rpc.FromDeviceRpcResponse; import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg; @@ -450,11 +455,19 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { dumpSessions(); } - void processCredentialsUpdate() { - sessions.forEach(this::notifyTransportAboutClosedSession); - attributeSubscriptions.clear(); - rpcSubscriptions.clear(); - dumpSessions(); + void processCredentialsUpdate(TbActorMsg msg) { + if (((DeviceCredentialsUpdateNotificationMsg) msg).getDeviceCredentials().getCredentialsType() == DeviceCredentialsType.LWM2M_CREDENTIALS) { + log.info("1) LwM2Mtype: "); + sessions.forEach((k, v) -> { + notifyTransportAboutProfileUpdate(k, v, ((DeviceCredentialsUpdateNotificationMsg) msg).getDeviceCredentials()); + }); + } else { + sessions.forEach(this::notifyTransportAboutClosedSession); + attributeSubscriptions.clear(); + rpcSubscriptions.clear(); + dumpSessions(); + + } } private void notifyTransportAboutClosedSession(UUID sessionId, SessionInfoMetaData sessionMd) { @@ -465,6 +478,18 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { systemContext.getTbCoreToTransportService().process(sessionMd.getSessionInfo().getNodeId(), msg); } + void notifyTransportAboutProfileUpdate(UUID sessionId, SessionInfoMetaData sessionMd, DeviceCredentials deviceCredentials) { + log.info("2) LwM2Mtype: "); + TransportProtos.ToTransportUpdateCredentialsProto.Builder notification = TransportProtos.ToTransportUpdateCredentialsProto.newBuilder(); + notification.addCredentialsId(deviceCredentials.getCredentialsId()); + notification.addCredentialsValue(deviceCredentials.getCredentialsValue()); + ToTransportMsg msg = ToTransportMsg.newBuilder() + .setSessionIdMSB(sessionId.getMostSignificantBits()) + .setSessionIdLSB(sessionId.getLeastSignificantBits()) + .setToTransportUpdateCredentialsNotification(notification).build(); + systemContext.getTbCoreToTransportService().process(sessionMd.getSessionInfo().getNodeId(), msg); + } + void processNameOrTypeUpdate(DeviceNameOrTypeUpdateMsg msg) { this.deviceName = msg.getDeviceName(); this.deviceType = msg.getDeviceType(); diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index 869cbea127..945e1d4c83 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -92,6 +92,7 @@ import org.thingsboard.server.queue.discovery.PartitionService; import org.thingsboard.server.queue.provider.TbQueueProducerProvider; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.component.ComponentDiscoveryService; +import org.thingsboard.server.service.lwm2m.LwM2MModelsRepository; import org.thingsboard.server.service.profile.TbDeviceProfileCache; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.service.queue.TbClusterService; @@ -211,6 +212,9 @@ public abstract class BaseController { @Autowired protected TbDeviceProfileCache deviceProfileCache; + @Autowired + protected LwM2MModelsRepository lwM2MModelsRepository; + @Value("${server.log_controller_error_stack_trace}") @Getter private boolean logControllerErrorStackTrace; diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java index da5d705ef8..e2db45884f 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -278,9 +278,8 @@ public class DeviceController extends BaseController { try { Device device = checkDeviceId(deviceCredentials.getDeviceId(), Operation.WRITE_CREDENTIALS); DeviceCredentials result = checkNotNull(deviceCredentialsService.updateDeviceCredentials(getCurrentUser().getTenantId(), deviceCredentials)); - - tbClusterService.pushMsgToCore(new DeviceCredentialsUpdateNotificationMsg(getCurrentUser().getTenantId(), deviceCredentials.getDeviceId()), null); - + //log.info("0 LwM2M CredentialsUpdate start) + tbClusterService.pushMsgToCore(new DeviceCredentialsUpdateNotificationMsg(getCurrentUser().getTenantId(), deviceCredentials.getDeviceId(), result), null); logEntityAction(device.getId(), device, device.getCustomerId(), ActionType.CREDENTIALS_UPDATED, null, deviceCredentials); diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceLwm2mController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceLwm2mController.java new file mode 100644 index 0000000000..76915fbed1 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceLwm2mController.java @@ -0,0 +1,75 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.controller; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; +import org.thingsboard.server.common.data.exception.ThingsboardException; +import org.thingsboard.server.common.data.lwm2m.LwM2mObject; +import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig; +import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.queue.util.TbCoreComponent; + +import java.util.List; + +@Slf4j +@RestController +@TbCoreComponent +@RequestMapping("/api") +public class DeviceLwm2mController extends BaseController { + + + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") + @RequestMapping(value = "/lwm2m/deviceProfile/{objectIds}", method = RequestMethod.GET) + @ResponseBody + public List getLwm2mListObjects(@PathVariable("objectIds") int[] objectIds) throws ThingsboardException { + try { + return lwM2MModelsRepository.getLwm2mObjects(objectIds, null); + } catch (Exception e) { + throw handleException(e); + } + } + + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") + @RequestMapping(value = "/lwm2m/deviceProfile/objects", params = {"pageSize", "page"}, method = RequestMethod.GET) + @ResponseBody + public PageData getLwm2mListObjects(@RequestParam int pageSize, + @RequestParam int page, + @RequestParam(required = false) String textSearch, + @RequestParam(required = false) String sortProperty, + @RequestParam(required = false) String sortOrder) throws ThingsboardException { + try { + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); + return checkNotNull(lwM2MModelsRepository.findDeviceLwm2mObjects(getTenantId(), pageLink)); + } catch (Exception e) { + throw handleException(e); + } + } + + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") + @RequestMapping(value = "/lwm2m/deviceProfile/bootstrap/{securityMode}/{bootstrapServerIs}", method = RequestMethod.GET) + @ResponseBody + public ServerSecurityConfig getLwm2mBootstrapSecurityInfo(@PathVariable("securityMode") String securityMode, + @PathVariable("bootstrapServerIs") boolean bootstrapServerIs) throws ThingsboardException { + try { + return lwM2MModelsRepository.getBootstrapSecurityInfo(securityMode, bootstrapServerIs); + } catch (Exception e) { + throw handleException(e); + } + } +} diff --git a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MModelsRepository.java b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MModelsRepository.java new file mode 100644 index 0000000000..e314cd8f51 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MModelsRepository.java @@ -0,0 +1,256 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.service.lwm2m; + + +import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.model.ObjectModel; +import org.eclipse.leshan.core.util.Hex; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.data.domain.PageImpl; +import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.lwm2m.*; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.transport.lwm2m.LwM2MTransportConfigBootstrap; +import org.thingsboard.server.common.transport.lwm2m.LwM2MTransportConfigServer; +import org.thingsboard.server.dao.service.Validator; +import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode; + +import java.math.BigInteger; +import java.security.*; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPublicKeySpec; +import java.security.spec.ECPoint; +import java.security.spec.KeySpec; +import java.util.List; +import java.util.ArrayList; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import static org.thingsboard.server.dao.service.Validator.validateId; + +@Slf4j +@Service +@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true') || '${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core'") +public class LwM2MModelsRepository { + + private static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; + + @Autowired + LwM2MTransportConfigServer contextServer; + + + @Autowired + LwM2MTransportConfigBootstrap contextBootStrap; + + /** + * @param objectIds + * @param textSearch + * @return list of LwM2mObject + * Filter by Predicate (uses objectIds, if objectIds is null then it uses textSearch, + * if textSearch is null then it uses AllList from List) + */ + public List getLwm2mObjects(int[] objectIds, String textSearch) { + return getLwm2mObjects((objectIds != null && objectIds.length > 0) ? + (ObjectModel element) -> IntStream.of(objectIds).anyMatch(x -> x == element.id) : + (textSearch != null && !textSearch.isEmpty()) ? (ObjectModel element) -> element.name.contains(textSearch) : null); + } + + /** + * @param predicate + * @return list of LwM2mObject + */ + private List getLwm2mObjects(Predicate predicate) { + List lwM2mObjects = new ArrayList<>(); + List listObjects = (predicate == null) ? this.contextServer.getModelsValue() : + contextServer.getModelsValue().stream() + .filter(predicate) + .collect(Collectors.toList()); + listObjects.forEach(obj -> { + LwM2mObject lwM2mObject = new LwM2mObject(); + lwM2mObject.setId(obj.id); + lwM2mObject.setName(obj.name); + lwM2mObject.setMultiple(obj.multiple); + lwM2mObject.setMandatory(obj.mandatory); + LwM2mInstance instance = new LwM2mInstance(); + instance.setId(0); + List resources = new ArrayList<>(); + obj.resources.forEach((k, v) -> { + if (!v.operations.isExecutable()) { + LwM2mResource resource = new LwM2mResource(k, v.name, false, false, false); + resources.add(resource); + } + }); + instance.setResources(resources.stream().toArray(LwM2mResource[]::new)); + lwM2mObject.setInstances(new LwM2mInstance[]{instance}); + lwM2mObjects.add(lwM2mObject); + }); + return lwM2mObjects; + } + + /** + * @param tenantId + * @param pageLink + * @return List of LwM2mObject in PageData format + */ + public PageData findDeviceLwm2mObjects(TenantId tenantId, PageLink pageLink) { + log.trace("Executing findDeviceProfileInfos tenantId [{}], pageLink [{}]", tenantId, pageLink); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + Validator.validatePageLink(pageLink); + return this.findLwm2mListObjects(pageLink); + } + + /** + * @param pageLink + * @return List of LwM2mObject in PageData format, filter == TextSearch + * PageNumber = 1, PageSize = List.size() + */ + public PageData findLwm2mListObjects(PageLink pageLink) { + PageImpl page = new PageImpl(getLwm2mObjects(null, pageLink.getTextSearch())); + PageData pageData = new PageData(page.getContent(), page.getTotalPages(), page.getTotalElements(), page.hasNext()); + return pageData; + } + + /** + * + * @param securityMode + * @param bootstrapServerIs + * @return ServerSecurityConfig more value is default: Important - port, host, publicKey + */ + public ServerSecurityConfig getBootstrapSecurityInfo(String securityMode, boolean bootstrapServerIs) { + LwM2MSecurityMode lwM2MSecurityMode = LwM2MSecurityMode.fromSecurityMode(securityMode.toLowerCase()); + return getBootstrapServer(bootstrapServerIs, lwM2MSecurityMode); + } + + /** + * + * @param bootstrapServerIs + * @param mode + * @return ServerSecurityConfig more value is default: Important - port, host, publicKey + */ + private ServerSecurityConfig getBootstrapServer(boolean bootstrapServerIs, LwM2MSecurityMode mode) { + ServerSecurityConfig bsServ = new ServerSecurityConfig(); + if (bootstrapServerIs) { + switch (mode) { + case NO_SEC: + bsServ.setHost(contextBootStrap.getBootstrapHost()); + bsServ.setPort(contextBootStrap.getBootstrapPort()); + bsServ.setServerPublicKey(""); + break; + case PSK: + bsServ.setHost(contextBootStrap.getBootstrapSecureHost()); + bsServ.setPort(contextBootStrap.getBootstrapSecurePort()); + bsServ.setServerPublicKey(""); + break; + case RPK: + bsServ.setHost(contextBootStrap.getBootstrapSecureHost()); + bsServ.setPort(contextBootStrap.getBootstrapSecurePort()); + bsServ.setServerPublicKey(getRPKPublicKey(this.contextBootStrap.getBootstrapPublicX(), this.contextBootStrap.getBootstrapPublicY())); + break; + case X509: + bsServ.setHost(contextBootStrap.getBootstrapSecureHost()); + bsServ.setPort(contextBootStrap.getBootstrapSecurePortCert()); + bsServ.setServerPublicKey(getServerPublicKeyX509(contextBootStrap.getBootstrapAlias())); + break; + default: + break; + } + } else { + bsServ.setBootstrapServerIs(bootstrapServerIs); + bsServ.setServerId(123); + switch (mode) { + case NO_SEC: + bsServ.setHost(contextServer.getServerHost()); + bsServ.setPort(contextServer.getServerPort()); + bsServ.setServerPublicKey(""); + break; + case PSK: + bsServ.setHost(contextServer.getServerSecureHost()); + bsServ.setPort(contextServer.getServerSecurePort()); + bsServ.setServerPublicKey(""); + break; + case RPK: + bsServ.setHost(contextServer.getServerSecureHost()); + bsServ.setPort(contextServer.getServerSecurePort()); + bsServ.setServerPublicKey(getRPKPublicKey(this.contextServer.getServerPublicX(), this.contextServer.getServerPublicY())); + break; + case X509: + bsServ.setHost(contextServer.getServerSecureHost()); + bsServ.setPort(contextServer.getServerSecurePortCert()); + bsServ.setServerPublicKey(getServerPublicKeyX509(contextServer.getServerAlias())); + break; + default: + break; + } + } + return bsServ; + } + + /** + * + * @param alias + * @return PublicKey format HexString or null + */ + private String getServerPublicKeyX509 (String alias) { + try { + X509Certificate serverCertificate = (X509Certificate) contextServer.getKeyStoreValue().getCertificate(alias); + return Hex.encodeHexString(serverCertificate.getEncoded()); + } catch (CertificateEncodingException | KeyStoreException e) { + e.printStackTrace(); + } + return null; + } + + /** + * + * @param publicServerX + * @param publicServerY + * @return PublicKey format HexString or null + */ + private String getRPKPublicKey(String publicServerX, String publicServerY) { + try { + /** Get Elliptic Curve Parameter spec for secp256r1 */ + AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC"); + algoParameters.init(new ECGenParameterSpec("secp256r1")); + ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class); + if (publicServerX != null && !publicServerX.isEmpty() && publicServerY != null && !publicServerY.isEmpty()) { + /** Get point values */ + byte[] publicX = Hex.decodeHex(publicServerX.toCharArray()); + byte[] publicY = Hex.decodeHex(publicServerY.toCharArray()); + /** Create key specs */ + KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)), + parameterSpec); + /** Get keys */ + PublicKey publicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec); + if (publicKey != null && publicKey.getEncoded().length > 0 ) { + return Hex.encodeHexString(publicKey.getEncoded()); + } + } + } catch (GeneralSecurityException | IllegalArgumentException e) { + log.error("[{}] Failed generate Server RPK for profile", e.getMessage()); + throw new RuntimeException(e); + } + return null; + } +} + diff --git a/application/src/main/java/org/thingsboard/server/service/security/device/DefaultDeviceAuthService.java b/application/src/main/java/org/thingsboard/server/service/security/device/DefaultDeviceAuthService.java index c13cb5529a..27c7dce6ef 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/device/DefaultDeviceAuthService.java +++ b/application/src/main/java/org/thingsboard/server/service/security/device/DefaultDeviceAuthService.java @@ -53,6 +53,8 @@ public class DefaultDeviceAuthService implements DeviceAuthService { return DeviceAuthResult.of(credentials.getDeviceId()); case X509_CERTIFICATE: return DeviceAuthResult.of(credentials.getDeviceId()); + case LWM2M_CREDENTIALS: + return DeviceAuthResult.of(credentials.getDeviceId()); default: return DeviceAuthResult.of("Credentials Type is not supported yet!"); } @@ -65,4 +67,4 @@ public class DefaultDeviceAuthService implements DeviceAuthService { } } -} \ No newline at end of file +} diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java index 5b3ad05ee9..c822880310 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java @@ -201,6 +201,7 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer } @Override + public void saveAndNotify(TenantId tenantId, EntityId entityId, String scope, List attributes, FutureCallback callback) { saveAndNotify(tenantId, entityId, scope, attributes, true, callback); } diff --git a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java index 98f5708bad..0bdeaf360e 100644 --- a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java +++ b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java @@ -69,6 +69,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponse import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceTokenRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509CertRequestMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceLwM2MCredentialsRequestMsg; import org.thingsboard.server.queue.common.TbProtoQueueMsg; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.dao.device.provision.ProvisionFailedException; @@ -149,6 +150,13 @@ public class DefaultTransportApiService implements TransportApiService { } else if (transportApiRequestMsg.hasEntityProfileRequestMsg()) { return Futures.transform(handle(transportApiRequestMsg.getEntityProfileRequestMsg()), value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); + } else if (transportApiRequestMsg.hasLwM2MRequestMsg()) { + return Futures.transform(handle(transportApiRequestMsg.getLwM2MRequestMsg()), + value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); + } else if (transportApiRequestMsg.hasValidateDeviceLwM2MCredentialsRequestMsg()) { + ValidateDeviceLwM2MCredentialsRequestMsg msg = transportApiRequestMsg.getValidateDeviceLwM2MCredentialsRequestMsg(); + return Futures.transform(validateCredentials(msg.getCredentialsId(), DeviceCredentialsType.LWM2M_CREDENTIALS), + value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); } else if (transportApiRequestMsg.hasProvisionDeviceRequestMsg()) { return Futures.transform(handle(transportApiRequestMsg.getProvisionDeviceRequestMsg()), value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); @@ -396,4 +404,40 @@ public class DefaultTransportApiService implements TransportApiService { return TransportApiResponseMsg.newBuilder() .setValidateCredResponseMsg(ValidateDeviceCredentialsResponseMsg.getDefaultInstance()).build(); } + + private ListenableFuture handle(TransportProtos.LwM2MRequestMsg requestMsg) { + if (requestMsg.hasRegistrationMsg()) { + return handleRegistration(requestMsg.getRegistrationMsg()); + } else { + return Futures.immediateFailedFuture(new RuntimeException("Not supported!")); + } + } + + private ListenableFuture handleRegistration(TransportProtos.LwM2MRegistrationRequestMsg msg) { + TenantId tenantId = new TenantId(UUID.fromString(msg.getTenantId())); + String deviceName = msg.getEndpoint(); + Lock deviceCreationLock = deviceCreationLocks.computeIfAbsent(deviceName, id -> new ReentrantLock()); + deviceCreationLock.lock(); + try { + Device device = deviceService.findDeviceByTenantIdAndName(tenantId, deviceName); + if (device == null) { + device = new Device(); + device.setTenantId(tenantId); + device.setName(deviceName); + device.setType("LwM2M"); + device = deviceService.saveDevice(device); + deviceStateService.onDeviceAdded(device); + } + TransportProtos.LwM2MRegistrationResponseMsg registrationResponseMsg = + TransportProtos.LwM2MRegistrationResponseMsg.newBuilder() + .setDeviceInfo(getDeviceInfoProto(device)).build(); + TransportProtos.LwM2MResponseMsg responseMsg = TransportProtos.LwM2MResponseMsg.newBuilder().setRegistrationMsg(registrationResponseMsg).build(); + return Futures.immediateFuture(TransportApiResponseMsg.newBuilder().setLwM2MResponseMsg(responseMsg).build()); + } catch (JsonProcessingException e) { + log.warn("[{}][{}] Failed to lookup device by gateway id and name", tenantId, deviceName, e); + throw new RuntimeException(e); + } finally { + deviceCreationLock.unlock(); + } + } } diff --git a/application/src/main/resources/banner.txt b/application/src/main/resources/banner.txt index 791f878366..111465dd8a 100644 --- a/application/src/main/resources/banner.txt +++ b/application/src/main/resources/banner.txt @@ -1,3 +1,10 @@ + ______ __ _ __ __ + /_ __/ / /_ (_) ____ ____ _ _____ / /_ ____ ____ _ _____ ____/ / + / / / __ \ / / / __ \ / __ `/ / ___/ / __ \ / __ \ / __ `/ / ___/ / __ / + / / / / / / / / / / / / / /_/ / (__ ) / /_/ // /_/ // /_/ / / / / /_/ / +/_/ /_/ /_/ /_/ /_/ /_/ \__, / /____/ /_.___/ \____/ \__,_/ /_/ \__,_/ + /____/ + =================================================== :: ${application.title} :: ${application.formatted-version} =================================================== diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 06661d9b58..5dfbdbebd8 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -433,7 +433,7 @@ spring: database-platform: "${SPRING_JPA_DATABASE_PLATFORM:org.hibernate.dialect.PostgreSQLDialect}" datasource: driverClassName: "${SPRING_DRIVER_CLASS_NAME:org.postgresql.Driver}" - url: "${SPRING_DATASOURCE_URL:jdbc:postgresql://localhost:5432/thingsboard}" + url: "${SPRING_DATASOURCE_URL:jdbc:postgresql://localhost:5432/thingsboard_ce_3_2_2}" username: "${SPRING_DATASOURCE_USERNAME:postgres}" password: "${SPRING_DATASOURCE_PASSWORD:postgres}" hikari: @@ -488,7 +488,7 @@ js: # Built-in JVM JavaScript environment properties local: # Use Sandboxed (secured) JVM JavaScript environment - use_js_sandbox: "${USE_LOCAL_JS_SANDBOX:true}" + use_js_sandbox: "${USE_LOCAL_JS_SANDBOX:false}" # Specify thread pool size for JavaScript sandbox resource monitor monitor_thread_pool_size: "${LOCAL_JS_SANDBOX_MONITOR_THREAD_POOL_SIZE:4}" # Maximum CPU time in milliseconds allowed for script execution @@ -565,6 +565,74 @@ transport: bind_address: "${COAP_BIND_ADDRESS:0.0.0.0}" bind_port: "${COAP_BIND_PORT:5683}" timeout: "${COAP_TIMEOUT:10000}" + # Local LwM2M transport parameters + lwm2m: + # Enable/disable lvm2m transport protocol. + enabled: "${LWM2M_ENABLED:true}" + # We choose a default timeout a bit higher to the MAX_TRANSMIT_WAIT(62-93s) which is the time from starting to + # send a Confirmable message to the time when an acknowledgement is no longer expected. + # DEFAULT_TIMEOUT = 2 * 60 * 1000l; 2 min in ms + timeout: "${LWM2M_TIMEOUT:120000}" +# model_path_file: "${LWM2M_MODEL_PATH_FILE:./common/transport/lwm2m/src/main/resources/models/}" + model_path_file: "${LWM2M_MODEL_PATH_FILE:}" + support_deprecated_ciphers_enable: "${LWM2M_SUPPORT_DEPRECATED_CIPHERS_ENABLED:true}" + secure: + # Only Certificate_x509: + # To get helps about files format and how to generate it, see: https://github.com/eclipse/leshan/wiki/Credential-files-format + # Create new X509 Certificates: common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh + key_store_type: "${LWM2M_KEYSTORE_TYPE:JKS}" + # key_store_type: "${LWM2M_KEYSTORE_TYPE:PKCS12}" +# key_store_path_file: "${KEY_STORE_PATH_FILE:/usr/share/thingsboard/conf/credentials/serverKeyStore.jks}" + key_store_path_file: "${KEY_STORE_PATH_FILE:}" + key_store_password: "${LWM2M_KEYSTORE_PASSWORD_SERVER:server_ks_password}" + root_alias: "${LWM2M_SERVER_ROOT_CA:rootca}" + enable_gen_psk_rpk: "${ENABLE_GEN_PSK_RPK:true}" + server: + bind_address: "${LWM2M_BIND_ADDRESS:0.0.0.0}" + bind_port: "${LWM2M_BIND_PORT:5685}" + bind_port_cert: "${LWM2M_BIND_PORT_CERT:5687}" + secure: + start_all: "${START_SERVER_ALL:true}" + #leshan.core (V1_1) + #DTLS security modes: + #0: Pre-Shared Key mode + #1: Raw Public Key mode + #2: Certificate mode X509 + #3: NoSec mode * + #OMA-TS-LightweightM2M_Core-V1_1_1-20190617-A (add) + #4: Certificate mode X509 with EST + # If only startAll == false + dtls_mode: "${LWM2M_SECURITY_MODE:1}" + bind_address: "${LWM2M_BIND_ADDRESS:0.0.0.0}" + bind_port: "${LWM2M_BIND_PORT_SEC:5686}" + bind_port_cert: "${LWM2M_BIND_PORT_SEC_CERT:5688}" + # Only RPK: Public & Private Key +# create_rpk: "${CREATE_RPK:}" + public_x: "${LWM2M_SERVER_PUBLIC_X:405354ea8893471d9296afbc8b020a5c6201b0bb25812a53b849d4480fa5f069}" + public_y: "${LWM2M_SERVER_PUBLIC_Y:30c9237e946a3a1692c1cafaa01a238a077f632c99371348337512363f28212b}" + private_s: "${LWM2M_SERVER_PRIVATE_S:274671fe40ce937b8a6352cf0a418e8a39e4bf0bb9bf74c910db953c20c73802}" + # Only Certificate_x509: + alias: "${LWM2M_KEYSTORE_ALIAS_SERVER:server}" + bootstrap: + enable: "${BOOTSTRAP:true}" + bind_address: "${LWM2M_BIND_ADDRESS_BS:0.0.0.0}" + bind_port: "${LWM2M_BIND_PORT_BS:5689}" + bind_port_cert: "${LWM2M_BIND_PORT_SER_BS:5691}" + secure: + start_all: "${START_BOOTSTRAP_ALL:true}" + # If only startAll == false + dtls_mode: "${LWM2M_SECURITY_MODE_BS:1}" + bind_address: "${LWM2M_BIND_ADDRESS_BS:0.0.0.0}" + bind_port: "${LWM2M_BIND_PORT_SEC_BS:5690}" + bind_port_cert: "${LWM2M_BIND_PORT_SEC_CERT_BS:5692}" + # Only RPK: Public & Private Key + public_x: "${LWM2M_SERVER_PUBLIC_X_BS:993ef2b698c6a9c0c1d8be78b13a9383c0854c7c7c7a504d289b403794648183}" + public_y: "${LWM2M_SERVER_PUBLIC_Y_BS:267412d5fc4e5ceb2257cb7fd7f76ebdac2fa9aa100afb162e990074cc0bfaa2}" + private_s: "${LWM2M_SERVER_PRIVATE_S_BS:9dbdbb073fc63570693a9aaf1013414e261c571f27e27fc6a8c1c2ad9347875a}" + # Only Certificate_x509: + alias: "${LWM2M_KEYSTORE_ALIAS_BOOTSTRAP:bootstrap}" + # Redis + redis_url: "${LWM2M_REDIS_URL:''}" swagger: api_path_regex: "${SWAGGER_API_PATH_REGEX:/api.*}" diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mInstance.java b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mInstance.java new file mode 100644 index 0000000000..4545e4dc0a --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mInstance.java @@ -0,0 +1,25 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.lwm2m; + +import lombok.Data; + +@Data +public class LwM2mInstance { + int id; + LwM2mResource [] resources; + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mObject.java b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mObject.java new file mode 100644 index 0000000000..4bd700fdf9 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mObject.java @@ -0,0 +1,27 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.lwm2m; + +import lombok.Data; + +@Data +public class LwM2mObject { + int id; + String name; + boolean multiple; + boolean mandatory; + LwM2mInstance [] instances; +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mResource.java b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mResource.java new file mode 100644 index 0000000000..7228f02760 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mResource.java @@ -0,0 +1,63 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.lwm2m; + +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.util.stream.Stream; + +@Data +@AllArgsConstructor +public class LwM2mResource { + int id; + String name; + boolean observe; + boolean attribute; + boolean telemetry; + String keyName; + + public LwM2mResource(int id, String name, boolean observe, boolean attribute, boolean telemetry) { + this.id = id; + this.name = name; + this.observe = observe; + this.attribute = attribute; + this.telemetry = telemetry; + this.keyName = getCamelCase (this.name); + } + + private String getCamelCase (String name) { + name = name.replaceAll("-", " "); + name = name.replaceAll("_", " "); + String [] nameCamel1 = name.split(" "); + String [] nameCamel2 = new String[nameCamel1.length]; + int[] idx = { 0 }; + Stream.of(nameCamel1).forEach((s -> { + nameCamel2[idx[0]] = toProperCase(idx[0]++, s); + })); + return String.join("", nameCamel2); + } + + private String toProperCase(int idx, String s) { + if (!s.isEmpty() && s.length()> 0) { + String s1 = (idx == 0) ? s.substring(0, 1).toLowerCase() : s.substring(0, 1).toUpperCase(); + String s2 = ""; + if (s.length()> 1) s2 = s.substring(1).toLowerCase(); + s = s1 + s2; + } + return s; + } +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/ServerSecurityConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/ServerSecurityConfig.java new file mode 100644 index 0000000000..3f7f1d543c --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/ServerSecurityConfig.java @@ -0,0 +1,34 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.lwm2m; + +import lombok.Builder; +import lombok.Data; + +@Data +public class ServerSecurityConfig { + String host; + Integer port; + String serverPublicKey; + @Builder.Default + boolean bootstrapServerIs = true; + @Builder.Default + Integer clientHoldOffTime = 1; + @Builder.Default + Integer serverId = 111; + @Builder.Default + Integer bootstrapServerAccountTimeout = 0; +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/security/DeviceCredentialsType.java b/common/data/src/main/java/org/thingsboard/server/common/data/security/DeviceCredentialsType.java index e7faf1b5ce..84a634a100 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/security/DeviceCredentialsType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/security/DeviceCredentialsType.java @@ -19,6 +19,8 @@ public enum DeviceCredentialsType { ACCESS_TOKEN, X509_CERTIFICATE, - MQTT_BASIC + MQTT_BASIC, + LWM2M_CREDENTIALS + } diff --git a/common/queue/src/main/proto/queue.proto b/common/queue/src/main/proto/queue.proto index 325a517988..08a0d0ba97 100644 --- a/common/queue/src/main/proto/queue.proto +++ b/common/queue/src/main/proto/queue.proto @@ -183,6 +183,47 @@ message GetEntityProfileRequestMsg { int64 entityIdLSB = 3; } +message LwM2MRegistrationRequestMsg { + string tenantId = 1; + string endpoint = 2; +} + +message LwM2MRegistrationResponseMsg { + DeviceInfoProto deviceInfo = 1; +} + +message LwM2MRequestMsg { + LwM2MRegistrationRequestMsg registrationMsg = 1; +} + +message LwM2MResponseMsg { + LwM2MRegistrationResponseMsg registrationMsg = 1; +} + +message ValidateDeviceLwM2MCredentialsRequestMsg { + string credentialsId = 1; +} + +message ToTransportUpdateCredentialsProto { + repeated string credentialsId = 1; + repeated string credentialsValue = 2; +} + +message GetTenantRoutingInfoRequestMsg { + int64 tenantIdMSB = 1; + int64 tenantIdLSB = 2; +} + +message GetTenantRoutingInfoResponseMsg { + bool isolatedTbCore = 1; + bool isolatedTbRuleEngine = 2; +} + +message GetDeviceProfileRequestMsg { + int64 profileIdMSB = 1; + int64 profileIdLSB = 2; +} + message GetEntityProfileResponseMsg { string entityType = 1; bytes data = 2; @@ -479,8 +520,10 @@ message TransportApiRequestMsg { ValidateDeviceX509CertRequestMsg validateX509CertRequestMsg = 2; GetOrCreateDeviceFromGatewayRequestMsg getOrCreateDeviceRequestMsg = 3; GetEntityProfileRequestMsg entityProfileRequestMsg = 4; + LwM2MRequestMsg lwM2MRequestMsg = 5; ValidateBasicMqttCredRequestMsg validateBasicMqttCredRequestMsg = 6; ProvisionDeviceRequestMsg provisionDeviceRequestMsg = 7; + ValidateDeviceLwM2MCredentialsRequestMsg validateDeviceLwM2MCredentialsRequestMsg = 8; } /* Response from ThingsBoard Core Service to Transport Service */ @@ -489,6 +532,7 @@ message TransportApiResponseMsg { GetOrCreateDeviceFromGatewayResponseMsg getOrCreateDeviceResponseMsg = 2; GetEntityProfileResponseMsg entityProfileResponseMsg = 3; ProvisionDeviceResponseMsg provisionDeviceResponseMsg = 4; + LwM2MResponseMsg lwM2MResponseMsg = 6; } /* Messages that are handled by ThingsBoard Core Service */ @@ -529,10 +573,10 @@ message ToTransportMsg { AttributeUpdateNotificationMsg attributeUpdateNotification = 5; ToDeviceRpcRequestMsg toDeviceRequest = 6; ToServerRpcResponseMsg toServerResponse = 7; - /* For Tenant, TenantProfile and DeviceProfile */ EntityUpdateMsg entityUpdateMsg = 8; EntityDeleteMsg entityDeleteMsg = 9; ProvisionDeviceResponseMsg provisionResponse = 10; + ToTransportUpdateCredentialsProto toTransportUpdateCredentialsNotification = 11; } message UsageStatsKVProto{ diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportContext.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportContext.java index d69cc1b25a..20e8cc7fdc 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportContext.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportContext.java @@ -24,6 +24,7 @@ import org.springframework.stereotype.Component; import org.thingsboard.server.common.transport.TransportContext; import org.thingsboard.server.transport.coap.adaptors.CoapTransportAdaptor; + /** * Created by ashvayka on 18.10.18. */ diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java index 63af515c00..685a637dab 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java @@ -16,14 +16,15 @@ package org.thingsboard.server.transport.coap; import lombok.extern.slf4j.Slf4j; +import org.eclipse.californium.core.CoapObserveRelation; import org.eclipse.californium.core.CoapResource; +import org.eclipse.californium.core.coap.CoAP; import org.eclipse.californium.core.coap.CoAP.ResponseCode; import org.eclipse.californium.core.coap.Request; +import org.eclipse.californium.core.network.Endpoint; import org.eclipse.californium.core.network.Exchange; -import org.eclipse.californium.core.network.ExchangeObserver; import org.eclipse.californium.core.server.resources.CoapExchange; import org.eclipse.californium.core.server.resources.Resource; -import org.springframework.util.ReflectionUtils; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.security.DeviceTokenCredentials; @@ -40,26 +41,26 @@ import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsRes import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceResponseMsg; -import java.lang.reflect.Field; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.UUID; +import java.util.Timer; +import java.util.TimerTask; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; @Slf4j public class CoapTransportResource extends CoapResource { - // coap://localhost:port/api/v1/DEVICE_TOKEN/[attributes|telemetry|rpc[/requestId]] private static final int ACCESS_TOKEN_POSITION = 3; private static final int FEATURE_TYPE_POSITION = 4; private static final int REQUEST_ID_POSITION = 5; private final CoapTransportContext transportContext; private final TransportService transportService; - private final Field observerField; private final long timeout; private final ConcurrentMap tokenToSessionIdMap = new ConcurrentHashMap<>(); private final Set rpcSubscriptions = ConcurrentHashMap.newKeySet(); @@ -73,9 +74,20 @@ public class CoapTransportResource extends CoapResource { // This is important to turn off existing observable logic in // CoapResource. We will have our own observe monitoring due to 1:1 // observe relationship. - this.setObservable(false); - observerField = ReflectionUtils.findField(Exchange.class, "observer"); - observerField.setAccessible(true); + this.setObservable(true); // enable observing + this.setObserveType(CoAP.Type.CON); // configure the notification type to CONs + this.getAttributes().setObservable(); // mark observable in the Link-Format + // schedule a periodic update task, otherwise let events call changed() + Timer timer = new Timer(); + timer.schedule(new UpdateTask(), 0, 5000); + } + + private class UpdateTask extends TimerTask { + @Override + public void run() { + // .. periodic update of the resource + changed(); // notify all observers + } } @Override @@ -187,9 +199,7 @@ public class CoapTransportResource extends CoapResource { new CoapOkCallback(exchange)); break; case SUBSCRIBE_ATTRIBUTES_REQUEST: - attributeSubscriptions.add(sessionId); - advanced.setObserver(new CoapExchangeObserverProxy((ExchangeObserver) observerField.get(advanced), - registerAsyncCoapSession(exchange, request, sessionInfo, sessionId))); + transportService.registerSyncSession(sessionInfo, new CoapSessionListener(sessionId, exchange), transportContext.getTimeout()); transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.getDefaultInstance(), new CoapNoOpCallback(exchange)); @@ -206,8 +216,6 @@ public class CoapTransportResource extends CoapResource { break; case SUBSCRIBE_RPC_COMMANDS_REQUEST: rpcSubscriptions.add(sessionId); - advanced.setObserver(new CoapExchangeObserverProxy((ExchangeObserver) observerField.get(advanced), - registerAsyncCoapSession(exchange, request, sessionInfo, sessionId))); transportService.process(sessionInfo, TransportProtos.SubscribeToRPCMsg.getDefaultInstance(), new CoapNoOpCallback(exchange)); @@ -243,9 +251,6 @@ public class CoapTransportResource extends CoapResource { } catch (AdaptorException e) { log.trace("[{}] Failed to decode message: ", sessionId, e); exchange.respond(ResponseCode.BAD_REQUEST); - } catch (IllegalAccessException e) { - log.trace("[{}] Failed to process message: ", sessionId, e); - exchange.respond(ResponseCode.INTERNAL_SERVER_ERROR); } })); } @@ -459,24 +464,17 @@ public class CoapTransportResource extends CoapResource { } } - public class CoapExchangeObserverProxy implements ExchangeObserver { - - private final ExchangeObserver proxy; - private final String token; - - CoapExchangeObserverProxy(ExchangeObserver proxy, String token) { - super(); - this.proxy = proxy; - this.token = token; - } - - @Override - public void completed(Exchange exchange) { - proxy.completed(exchange); - TransportProtos.SessionInfoProto session = tokenToSessionIdMap.remove(token); - if (session != null) { - closeAndDeregister(session); - } + public class CoapExchangeObserverProxy extends CoapObserveRelation { + + /** + * Constructs a new CoapObserveRelation with the specified request. + * + * @param request the request + * @param endpoint the endpoint + * @param executor + */ + protected CoapExchangeObserverProxy(Request request, Endpoint endpoint, ScheduledThreadPoolExecutor executor) { + super(request, endpoint, executor); } } diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportService.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportService.java index a6813e488d..ba99d1b703 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportService.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportService.java @@ -18,8 +18,9 @@ package org.thingsboard.server.transport.coap; import lombok.extern.slf4j.Slf4j; import org.eclipse.californium.core.CoapResource; import org.eclipse.californium.core.CoapServer; + import org.eclipse.californium.core.network.CoapEndpoint; -import org.eclipse.californium.core.network.config.NetworkConfig; +import org.eclipse.californium.core.network.CoapEndpoint.Builder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Service; @@ -47,11 +48,15 @@ public class CoapTransportService { public void init() throws UnknownHostException { log.info("Starting CoAP transport..."); log.info("Starting CoAP transport server"); - this.server = new CoapServer(NetworkConfig.createStandardWithoutFile()); + this.server = new CoapServer(); createResources(); InetAddress addr = InetAddress.getByName(coapTransportContext.getHost()); InetSocketAddress sockAddr = new InetSocketAddress(addr, coapTransportContext.getPort()); - server.addEndpoint(new CoapEndpoint(sockAddr)); + Builder builder = new Builder(); + builder.setInetSocketAddress(sockAddr); + CoapEndpoint coapEndpoint = builder.build(); + + server.addEndpoint(coapEndpoint); server.start(); log.info("CoAP transport started!"); } diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/adaptors/JsonCoapAdaptor.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/adaptors/JsonCoapAdaptor.java index 28292f6c20..ef01657a7f 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/adaptors/JsonCoapAdaptor.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/adaptors/JsonCoapAdaptor.java @@ -31,6 +31,7 @@ import org.thingsboard.server.common.transport.adaptor.JsonConverter; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.transport.coap.CoapTransportResource; + import java.util.Arrays; import java.util.HashSet; import java.util.List; diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/DeviceEmulator.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/DeviceEmulator.java index ffc62280ec..e0347330fd 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/DeviceEmulator.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/DeviceEmulator.java @@ -28,6 +28,7 @@ import org.eclipse.californium.core.CoapClient; import org.eclipse.californium.core.CoapHandler; import org.eclipse.californium.core.CoapResponse; import org.eclipse.californium.core.coap.MediaTypeRegistry; +import org.eclipse.californium.elements.exception.ConnectorException; import org.thingsboard.server.common.msg.session.FeatureType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -61,7 +62,7 @@ public class DeviceEmulator { this.attributesClient = new CoapClient(getFeatureTokenUrl(host, port, token, FeatureType.ATTRIBUTES)); this.telemetryClient = new CoapClient(getFeatureTokenUrl(host, port, token, FeatureType.TELEMETRY)); this.rpcClient = new CoapClient(getFeatureTokenUrl(host, port, token, FeatureType.RPC)); - this.keys = keys.split(","); + this.keys = (keys != null && !keys.isEmpty()) ? keys.split(",") : null; } public void start() { @@ -72,11 +73,8 @@ public class DeviceEmulator { try { sendObserveRequest(rpcClient); while (!Thread.interrupted()) { - - sendRequest(attributesClient, createAttributesRequest()); sendRequest(telemetryClient, createTelemetryRequest()); - Thread.sleep(1000); } } catch (Exception e) { @@ -84,8 +82,8 @@ public class DeviceEmulator { } } - private void sendRequest(CoapClient client, JsonNode request) throws JsonProcessingException { - CoapResponse telemetryResponse = client.setTimeout(60000).post(mapper.writeValueAsString(request), + private void sendRequest(CoapClient client, JsonNode request) throws IOException, ConnectorException { + CoapResponse telemetryResponse = client.setTimeout((long) 60000).post(mapper.writeValueAsString(request), MediaTypeRegistry.APPLICATION_JSON); log.info("Response: {}, {}", telemetryResponse.getCode(), telemetryResponse.getResponseText()); } @@ -113,6 +111,7 @@ public class DeviceEmulator { @Override public void onError() { + log.info("Command Response Ack Error, No connect"); //Do nothing } }, mapper.writeValueAsString(response), MediaTypeRegistry.APPLICATION_JSON); @@ -157,6 +156,15 @@ public class DeviceEmulator { if (args.length != 4) { System.out.println("Usage: java -jar " + DeviceEmulator.class.getSimpleName() + ".jar host port device_token keys"); } + /** + * DeviceEmulator(String host, int port, String token, String keys) + * args[]: + * host = "localhost", + * port = 0, + * token = "{Tokrn device from thingboard}"), kSzbDRGwaZqZ6Y25gTLF + * keys = "{Telemetry}" + * + */ final DeviceEmulator emulator = new DeviceEmulator(args[0], Integer.parseInt(args[1]), args[2], args[3]); emulator.start(); Runtime.getRuntime().addShutdownHook(new Thread() { @@ -167,7 +175,6 @@ public class DeviceEmulator { }); } - private String getFeatureTokenUrl(String host, int port, String token, FeatureType featureType) { return getBaseUrl(host, port) + token + "/" + featureType.name().toLowerCase(); } diff --git a/common/transport/http/src/main/java/org/thingsboard/server/transport/http/DeviceApiController.java b/common/transport/http/src/main/java/org/thingsboard/server/transport/http/DeviceApiController.java index cdc2791839..600e7033ab 100644 --- a/common/transport/http/src/main/java/org/thingsboard/server/transport/http/DeviceApiController.java +++ b/common/transport/http/src/main/java/org/thingsboard/server/transport/http/DeviceApiController.java @@ -327,6 +327,7 @@ public class DeviceApiController { public void onToServerRpcResponse(ToServerRpcResponseMsg msg) { responseWriter.setResult(new ResponseEntity<>(JsonConverter.toJson(msg).toString(), HttpStatus.OK)); } + } private void reportActivity(SessionInfoProto sessionInfo) { diff --git a/common/transport/lwm2m/pom.xml b/common/transport/lwm2m/pom.xml new file mode 100644 index 0000000000..0e9d3d58cd --- /dev/null +++ b/common/transport/lwm2m/pom.xml @@ -0,0 +1,123 @@ + + + + 4.0.0 + + org.thingsboard.common + 3.2.0-SNAPSHOT + transport + + org.thingsboard.common.transport + lwm2m + jar + + Thingsboard LwM2M Transport Common + https://thingsboard.io + + + UTF-8 + ${basedir}/../../.. + + + + + org.thingsboard.common.transport + transport-api + + + org.springframework + spring-context-support + + + org.springframework + spring-context + + + org.slf4j + slf4j-api + + + org.slf4j + log4j-over-slf4j + + + ch.qos.logback + logback-core + + + ch.qos.logback + logback-classic + + + + org.eclipse.leshan + leshan-server-cf + + + + + + + org.eclipse.leshan + leshan-client-cf + + + + org.eclipse.leshan + leshan-server-redis + + + + + + + + + org.springframework.boot + spring-boot-starter-test + test + + + junit + junit + test + + + org.mockito + mockito-all + test + + + org.eclipse.californium + californium-core + ${californium.version} + test-jar + test + + + org.eclipse.californium + element-connector + ${californium.version} + test-jar + test + + + + diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerConfiguration.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerConfiguration.java new file mode 100644 index 0000000000..a1f056ff30 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerConfiguration.java @@ -0,0 +1,101 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.bootstrap; + +import lombok.extern.slf4j.Slf4j; +import org.eclipse.californium.scandium.config.DtlsConnectorConfig; +import org.eclipse.leshan.core.model.StaticModel; +import org.eclipse.leshan.server.bootstrap.BootstrapSessionManager; +import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServer; +import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServerBuilder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Component; +import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapSecurityStore; +import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MInMemoryBootstrapConfigStore; +import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MSetSecurityStoreBootstrap; +import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2mDefaultBootstrapSessionManager; +import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode; +import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportContextServer; +import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.X509; +import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.RPK; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.getCoapConfig; + +@Slf4j +@Component +@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true'&& '${transport.lwm2m.bootstrap.enable:false}'=='true') || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true'&& '${transport.lwm2m.bootstrap.enable}'=='true')") +public class LwM2MTransportBootstrapServerConfiguration { + + @Autowired + private LwM2MTransportContextBootstrap contextBs; + + @Autowired + private LwM2MTransportContextServer contextS; + + @Autowired + private LwM2MBootstrapSecurityStore lwM2MBootstrapSecurityStore; + + @Autowired + private LwM2MInMemoryBootstrapConfigStore lwM2MInMemoryBootstrapConfigStore; + + + @Primary + @Bean(name = "leshanBootstrapCert") + public LeshanBootstrapServer getLeshanBootstrapServerCert() { + log.info("Prepare and start BootstrapServerCert... PostConstruct"); + return getLeshanBootstrapServer(this.contextBs.getCtxBootStrap().getBootstrapPortCert(), this.contextBs.getCtxBootStrap().getBootstrapSecurePortCert(), X509); + } + + @Bean(name = "leshanBootstrapRPK") + public LeshanBootstrapServer getLeshanBootstrapServerRPK() { + log.info("Prepare and start BootstrapServerRPK... PostConstruct"); + return getLeshanBootstrapServer(this.contextBs.getCtxBootStrap().getBootstrapPort(), this.contextBs.getCtxBootStrap().getBootstrapSecurePort(), RPK); + } + + public LeshanBootstrapServer getLeshanBootstrapServer(Integer bootstrapPort, Integer bootstrapSecurePort, LwM2MSecurityMode dtlsMode) { + LeshanBootstrapServerBuilder builder = new LeshanBootstrapServerBuilder(); + builder.setLocalAddress(this.contextBs.getCtxBootStrap().getBootstrapHost(), bootstrapPort); + builder.setLocalSecureAddress(this.contextBs.getCtxBootStrap().getBootstrapSecureHost(), bootstrapSecurePort); + + /** Create CoAP Config */ + builder.setCoapConfig(getCoapConfig ()); + + /** ConfigStore */ + builder.setConfigStore(lwM2MInMemoryBootstrapConfigStore); + + /** SecurityStore */ + builder.setSecurityStore(lwM2MBootstrapSecurityStore); + + /** Define model provider (Create Models )*/ + builder.setModel(new StaticModel(contextS.getCtxServer().getModelsValue())); + + /** Create and Set DTLS Config */ + DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(); + dtlsConfig.setRecommendedCipherSuitesOnly(contextS.getCtxServer().isSupportDeprecatedCiphersEnable()); + builder.setDtlsConfig(dtlsConfig); + + /** Create credentials */ + new LwM2MSetSecurityStoreBootstrap(builder, contextBs, contextS, dtlsMode); + + BootstrapSessionManager sessionManager = new LwM2mDefaultBootstrapSessionManager(lwM2MBootstrapSecurityStore); + builder.setSessionManager(sessionManager); + + /** Create BootstrapServer */ + return builder.build(); + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerInitializer.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerInitializer.java new file mode 100644 index 0000000000..cb927a76b9 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerInitializer.java @@ -0,0 +1,70 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.bootstrap; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Service; +import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; + +@Slf4j +@Service +@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled}'=='true'&& '${transport.lwm2m.bootstrap.enable}'=='true') || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true'&& '${transport.lwm2m.bootstrap.enable}'=='true')") +public class LwM2MTransportBootstrapServerInitializer { + + @Autowired + @Qualifier("leshanBootstrapCert") + private LeshanBootstrapServer lhBServerCert; + + @Autowired + @Qualifier("leshanBootstrapRPK") + private LeshanBootstrapServer lhBServerRPK; + + @Autowired + private LwM2MTransportContextBootstrap contextBS; + + @PostConstruct + public void init() { + if (this.contextBS.getCtxBootStrap().isBootstrapStartAll()) { + this.lhBServerCert.start(); + this.lhBServerRPK.start(); + } + else { + if (this.contextBS.getCtxBootStrap().getBootStrapDtlsMode() == LwM2MSecurityMode.X509.code) { + this.lhBServerCert.start(); + } + else { + this.lhBServerRPK.start(); + } + } + } + + @PreDestroy + public void shutdown() throws InterruptedException { + log.info("Stopping LwM2M transport Bootstrap Server!"); + try { + lhBServerCert.destroy(); + lhBServerRPK.destroy(); + } finally { + } + log.info("LwM2M transport Bootstrap Server stopped!"); + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportContextBootstrap.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportContextBootstrap.java new file mode 100644 index 0000000000..041a6f2040 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportContextBootstrap.java @@ -0,0 +1,60 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.bootstrap; +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Component; +import org.thingsboard.server.common.transport.TransportContext; +import org.thingsboard.server.common.transport.lwm2m.LwM2MTransportConfigBootstrap; + +import javax.annotation.PostConstruct; + + +@Slf4j +@Component +@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true') || '${service.type:null}'=='monolith'") +public class LwM2MTransportContextBootstrap extends TransportContext { + + private LwM2MTransportConfigBootstrap ctxBootStrap; + @Autowired + LwM2MTransportConfigBootstrap lwM2MTransportConfigBootstarp; + + @PostConstruct + public void init() { + this.ctxBootStrap = lwM2MTransportConfigBootstarp; + } + + public LwM2MTransportConfigBootstrap getCtxBootStrap() { + return this.ctxBootStrap; + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java new file mode 100644 index 0000000000..51d37ad90e --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java @@ -0,0 +1,102 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.bootstrap.secure; + +import lombok.Builder; +import lombok.Data; +import org.eclipse.leshan.core.SecurityMode; +import org.eclipse.leshan.core.request.BindingMode; +import org.eclipse.leshan.core.util.Hex; +import org.eclipse.leshan.server.bootstrap.BootstrapConfig; + +import java.nio.charset.StandardCharsets; + +@Data +public class LwM2MBootstrapConfig { + /** + * interface BootstrapSecurityConfig + * servers: BootstrapServersSecurityConfig, + * bootstrapServer: ServerSecurityConfig, + * lwm2mServer: ServerSecurityConfig + * } + */ + /** -servers + * shortId: number, + * lifetime: number, + * defaultMinPeriod: number, + * notifIfDisabled: boolean, + * binding: string + * */ + @Builder.Default + LwM2MBootstrapServers servers; + + /** -bootstrapServer, lwm2mServer + * interface ServerSecurityConfig + * host?: string, + * port?: number, + * isBootstrapServer?: boolean, + * securityMode: string, + * clientPublicKeyOrId?: string, + * clientSecretKey?: string, + * serverPublicKey?: string; + * clientHoldOffTime?: number, + * serverId?: number, + * bootstrapServerAccountTimeout: number + * */ + LwM2MServerBootstrap bootstrapServer; + + LwM2MServerBootstrap lwm2mServer; + + public BootstrapConfig getLwM2MBootstrapConfig() { + BootstrapConfig configBs = new BootstrapConfig(); + /** Delete old security objects */ + configBs.toDelete.add("/0"); + configBs.toDelete.add("/1"); + /** Server Configuration (object 1) as defined in LWM2M 1.0.x TS. */ + BootstrapConfig.ServerConfig server0 = new BootstrapConfig.ServerConfig(); + server0.shortId = servers.getShortId(); + server0.lifetime = servers.getLifetime(); + server0.defaultMinPeriod = servers.getDefaultMinPeriod(); + server0.notifIfDisabled = servers.isNotifIfDisabled(); + server0.binding = BindingMode.valueOf(servers.getBinding()); + configBs.servers.put(0, server0); + /** Security Configuration (object 0) as defined in LWM2M 1.0.x TS. Bootstrap instance = 0 */ + this.bootstrapServer.setBootstrapServerIs(true); + configBs.security.put(0, setServerSecuruty(this.bootstrapServer.getHost(), this.bootstrapServer.getPort(), this.bootstrapServer.isBootstrapServerIs(), this.bootstrapServer.getSecurityMode(), this.bootstrapServer.getClientPublicKeyOrId(), this.bootstrapServer.getServerPublicKey(), this.bootstrapServer.getClientSecretKey(), this.bootstrapServer.getServerId())); + /** Security Configuration (object 0) as defined in LWM2M 1.0.x TS. Server instance = 1 */ + configBs.security.put(1, setServerSecuruty(this.lwm2mServer.getHost(), this.lwm2mServer.getPort(), this.lwm2mServer.isBootstrapServerIs(), this.lwm2mServer.getSecurityMode(), this.lwm2mServer.getClientPublicKeyOrId(), this.lwm2mServer.getServerPublicKey(), this.lwm2mServer.getClientSecretKey(), this.lwm2mServer.getServerId())); + return configBs; + } + + private BootstrapConfig.ServerSecurity setServerSecuruty(String host, Integer port, boolean bootstrapServer, String securityMode, String clientPublicKey, String serverPublicKey, String secretKey, int serverId) { + BootstrapConfig.ServerSecurity serverSecurity = new BootstrapConfig.ServerSecurity(); + serverSecurity.uri = "coaps://" + host + ":" + Integer.toString(port); + serverSecurity.bootstrapServer = bootstrapServer; + serverSecurity.securityMode = SecurityMode.valueOf(securityMode); + serverSecurity.publicKeyOrId = setPublicKeyOrId(clientPublicKey, securityMode); + serverSecurity.serverPublicKey = (serverPublicKey != null && !serverPublicKey.isEmpty()) ? Hex.decodeHex(serverPublicKey.toCharArray()) : new byte[]{}; + serverSecurity.secretKey = (secretKey != null && !secretKey.isEmpty()) ? Hex.decodeHex(secretKey.toCharArray()) : new byte[]{}; + serverSecurity.serverId = serverId; + return serverSecurity; + } + + private byte[] setPublicKeyOrId(String publicKeyOrIdStr, String securityMode) { + byte[] publicKey = (publicKeyOrIdStr == null || publicKeyOrIdStr.isEmpty()) ? new byte[]{} : + SecurityMode.valueOf(securityMode).equals(SecurityMode.PSK) ? publicKeyOrIdStr.getBytes(StandardCharsets.UTF_8) : + Hex.decodeHex(publicKeyOrIdStr.toCharArray()); + return publicKey; + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java new file mode 100644 index 0000000000..0b06f02547 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java @@ -0,0 +1,181 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.bootstrap.secure; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.JsonObject; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.SecurityMode; +import org.eclipse.leshan.core.util.Hex; +import org.eclipse.leshan.core.util.SecurityUtil; +import org.eclipse.leshan.server.bootstrap.BootstrapConfig; +import org.eclipse.leshan.server.bootstrap.EditableBootstrapConfigStore; +import org.eclipse.leshan.server.bootstrap.InvalidConfigurationException; +import org.eclipse.leshan.server.security.BootstrapSecurityStore; +import org.eclipse.leshan.server.security.SecurityInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Component; +import org.thingsboard.server.transport.lwm2m.secure.LwM2MGetSecurityInfo; +import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode; +import org.thingsboard.server.transport.lwm2m.secure.ReadResultSecurityStore; +import org.thingsboard.server.transport.lwm2m.utils.TypeServer; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.util.Arrays; +import java.util.List; + +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.*; + +@Slf4j +@Component("LwM2MBootstrapSecurityStore") +@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' && '${transport.lwm2m.bootstrap.enable:false}'=='true') || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true' && '${transport.lwm2m.bootstrap.enable}'=='true')") +public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { + + private final EditableBootstrapConfigStore bootstrapConfigStore; + + @Autowired + LwM2MGetSecurityInfo lwM2MGetSecurityInfo; + + public LwM2MBootstrapSecurityStore(EditableBootstrapConfigStore bootstrapConfigStore) { + this.bootstrapConfigStore = bootstrapConfigStore; + } + + @Override + public List getAllByEndpoint(String endPoint) { + String endPointKey = endPoint; + ReadResultSecurityStore store = lwM2MGetSecurityInfo.getSecurityInfo(endPointKey, TypeServer.BOOTSTRAP); + if (store.getBootstrapJsonCredential() != null) { + /** add value to store from BootstrapJson */ + this.setBootstrapConfigScurityInfo(store); + BootstrapConfig bsConfigNew = store.getBootstrapConfig(); + if (bsConfigNew != null) { + try { + for (String config : bootstrapConfigStore.getAll().keySet()) { + if (config.equals(endPoint)) { + bootstrapConfigStore.remove(config); + } + } + bootstrapConfigStore.add(endPoint, bsConfigNew); + } catch (InvalidConfigurationException e) { + e.printStackTrace(); + } + return store.getSecurityInfo() == null ? null : Arrays.asList(store.getSecurityInfo()); + } + } + return null; + } + + @Override + public SecurityInfo getByIdentity(String identity) { + ReadResultSecurityStore store = lwM2MGetSecurityInfo.getSecurityInfo(identity, TypeServer.BOOTSTRAP); + /** add value to store from BootstrapJson */ + this.setBootstrapConfigScurityInfo(store); + + if (store.getSecurityMode() < LwM2MSecurityMode.DEFAULT_MODE.code) { + BootstrapConfig bsConfig = store.getBootstrapConfig(); + if (bsConfig.security != null) { + try { + bootstrapConfigStore.add(store.getEndPoint(), bsConfig); + } catch (InvalidConfigurationException e) { + e.printStackTrace(); + } + return store.getSecurityInfo(); + } + } + return null; + } + + private void setBootstrapConfigScurityInfo(ReadResultSecurityStore store) { + /** BootstrapConfig */ + LwM2MBootstrapConfig lwM2MBootstrapConfig = this.getParametersBootstrap(store); + if (lwM2MBootstrapConfig != null) { + /** Security info */ + switch (SecurityMode.valueOf(lwM2MBootstrapConfig.getBootstrapServer().getSecurityMode())) { + /** Use RPK only */ + case PSK: + store.setSecurityInfo(SecurityInfo.newPreSharedKeyInfo(store.getEndPoint(), + lwM2MBootstrapConfig.getBootstrapServer().getClientPublicKeyOrId(), + Hex.decodeHex(lwM2MBootstrapConfig.getBootstrapServer().getClientSecretKey().toCharArray()))); + store.setSecurityMode(SecurityMode.PSK.code); + break; + case RPK: + try { + store.setSecurityInfo(SecurityInfo.newRawPublicKeyInfo(store.getEndPoint(), + SecurityUtil.publicKey.decode(Hex.decodeHex(lwM2MBootstrapConfig.getBootstrapServer().getClientPublicKeyOrId().toCharArray())))); + store.setSecurityMode(SecurityMode.RPK.code); + break; + } catch (IOException | GeneralSecurityException e) { + log.error("Unable to decode Client public key for [{}] [{}]", store.getEndPoint(), e.getMessage()); + } + case X509: + store.setSecurityInfo(SecurityInfo.newX509CertInfo(store.getEndPoint())); + store.setSecurityMode(SecurityMode.X509.code); + break; + case NO_SEC: + store.setSecurityMode(SecurityMode.NO_SEC.code); + store.setSecurityInfo(null); + break; + default: + } + BootstrapConfig bootstrapConfig = lwM2MBootstrapConfig.getLwM2MBootstrapConfig(); + store.setBootstrapConfig(bootstrapConfig); + } + } + + private LwM2MBootstrapConfig getParametersBootstrap(ReadResultSecurityStore store) { + try { + JsonObject bootstrapJsonCredential = store.getBootstrapJsonCredential(); + ObjectMapper mapper = new ObjectMapper(); + LwM2MBootstrapConfig lwM2MBootstrapConfig = mapper.readValue(bootstrapJsonCredential.toString(), LwM2MBootstrapConfig.class); + JsonObject bootstrapObject = getBootstrapParametersFromThingsboard(store.getDeviceProfile()); + lwM2MBootstrapConfig.servers = mapper.readValue(bootstrapObject.get(SERVERS).toString(), LwM2MBootstrapServers.class); + LwM2MServerBootstrap profileServerBootstrap = mapper.readValue(bootstrapObject.get(BOOTSTRAP_SERVER).toString(), LwM2MServerBootstrap.class); + LwM2MServerBootstrap profileLwm2mServer = mapper.readValue(bootstrapObject.get(LWM2M_SERVER).toString(), LwM2MServerBootstrap.class); + if (getValidatedSecurityMode(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap, lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer)) { + lwM2MBootstrapConfig.bootstrapServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap); + lwM2MBootstrapConfig.lwm2mServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer); + return lwM2MBootstrapConfig; + } + else { + log.error(" [{}] Different values SecurityMode between of client and profile.", store.getEndPoint()); + log.error(LOG_LW2M_ERROR + " getParametersBootstrap: [{}] Different values SecurityMode between of client and profile.", store.getEndPoint()); + String logMsg = String.format(LOG_LW2M_ERROR + " getParametersBootstrap: %s Different values SecurityMode between of client and profile.", store.getEndPoint()); +// sentLogsToThingsboard(logMsg, store.getEndPoint()); + return null; + } + } catch (JsonProcessingException e) { + log.error("Unable to decode Json or Certificate for [{}] [{}]", store.getEndPoint(), e.getMessage()); + return null; + } + } + + /** + * Bootstrap security have to sync between (bootstrapServer in credential and bootstrapServer in profile) + * and (lwm2mServer in credential and lwm2mServer in profile + * @param bootstrapFromCredential - Bootstrap -> Security of bootstrapServer in credential + * @param profileServerBootstrap - Bootstrap -> Security of bootstrapServer in profile + * @param lwm2mFromCredential - Bootstrap -> Security of lwm2mServer in credential + * @param profileLwm2mServer - Bootstrap -> Security of lwm2mServer in profile + * @return false if not sync between SecurityMode of Bootstrap credential and profile + */ + private boolean getValidatedSecurityMode(LwM2MServerBootstrap bootstrapFromCredential, LwM2MServerBootstrap profileServerBootstrap, LwM2MServerBootstrap lwm2mFromCredential, LwM2MServerBootstrap profileLwm2mServer) { + return (bootstrapFromCredential.getSecurityMode().equals(profileServerBootstrap.getSecurityMode()) && + lwm2mFromCredential.getSecurityMode().equals(profileLwm2mServer.getSecurityMode())); + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapServers.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapServers.java new file mode 100644 index 0000000000..ab5bf3eed2 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapServers.java @@ -0,0 +1,33 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.bootstrap.secure; + +import lombok.Builder; +import lombok.Data; + +@Data +public class LwM2MBootstrapServers { + @Builder.Default + private Integer shortId = 123; + @Builder.Default + private Integer lifetime = 300; + @Builder.Default + private Integer defaultMinPeriod = 1; + @Builder.Default + private boolean notifIfDisabled = true; + @Builder.Default + private String binding = "U"; +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MInMemoryBootstrapConfigStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MInMemoryBootstrapConfigStore.java new file mode 100644 index 0000000000..d4cbfe48f0 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MInMemoryBootstrapConfigStore.java @@ -0,0 +1,71 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.bootstrap.secure; + +import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.server.bootstrap.BootstrapConfig; +import org.eclipse.leshan.server.bootstrap.InMemoryBootstrapConfigStore; +import org.eclipse.leshan.server.bootstrap.InvalidConfigurationException; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Component; +import java.util.Map; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +@Slf4j +@Component("LwM2MInMemoryBootstrapConfigStore") +@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' && '${transport.lwm2m.bootstrap.enable:false}'=='true') || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true'&& '${transport.lwm2m.bootstrap.enable}'=='true')") +public class LwM2MInMemoryBootstrapConfigStore extends InMemoryBootstrapConfigStore { + private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); + private final Lock readLock = readWriteLock.readLock(); + private final Lock writeLock = readWriteLock.writeLock(); + + @Override + public Map getAll() { + readLock.lock(); + try { + return super.getAll(); + } finally { + readLock.unlock(); + } + } + + @Override + public void add(String endpoint, BootstrapConfig config) throws InvalidConfigurationException { + writeLock.lock(); + try { + addToStore(endpoint, config); + } finally { + writeLock.unlock(); + } + } + + @Override + public BootstrapConfig remove(String enpoint) { + writeLock.lock(); + try { + BootstrapConfig res = super.remove(enpoint); + return res; + } finally { + writeLock.unlock(); + } + } + + public void addToStore(String endpoint, BootstrapConfig config) throws InvalidConfigurationException { + super.add(endpoint, config); + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MServerBootstrap.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MServerBootstrap.java new file mode 100644 index 0000000000..fbd3a7e0a2 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MServerBootstrap.java @@ -0,0 +1,65 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.bootstrap.secure; + +import lombok.Builder; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.SecurityMode; + +@Slf4j +@Data +public class LwM2MServerBootstrap { + + @Builder.Default + String clientPublicKeyOrId = ""; + @Builder.Default + String clientSecretKey = ""; + @Builder.Default + String serverPublicKey = ""; + @Builder.Default + Integer clientHoldOffTime = 1; + @Builder.Default + Integer bootstrapServerAccountTimeout = 0; + + @Builder.Default + String host = "0.0.0.0"; + @Builder.Default + Integer port = 0; + + @Builder.Default + String securityMode = SecurityMode.NO_SEC.name(); + + @Builder.Default + Integer serverId = 123; + @Builder.Default + boolean bootstrapServerIs = false; + + public LwM2MServerBootstrap(){}; + + public LwM2MServerBootstrap(LwM2MServerBootstrap bootstrapFromCredential, LwM2MServerBootstrap profileServerBootstrap) { + this.clientPublicKeyOrId = bootstrapFromCredential.getClientPublicKeyOrId(); + this.clientSecretKey = bootstrapFromCredential.getClientSecretKey(); + this.serverPublicKey = profileServerBootstrap.getServerPublicKey(); + this.clientHoldOffTime = profileServerBootstrap.getClientHoldOffTime(); + this.bootstrapServerAccountTimeout = profileServerBootstrap.getBootstrapServerAccountTimeout(); + this.host = (profileServerBootstrap.getHost().equals("0.0.0.0")) ? "localhost" : profileServerBootstrap.getHost(); + this.port = profileServerBootstrap.getPort(); + this.securityMode = profileServerBootstrap.getSecurityMode(); + this.serverId = profileServerBootstrap.getServerId(); + this.bootstrapServerIs = profileServerBootstrap.bootstrapServerIs; + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MSetSecurityStoreBootstrap.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MSetSecurityStoreBootstrap.java new file mode 100644 index 0000000000..f648799204 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MSetSecurityStoreBootstrap.java @@ -0,0 +1,205 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.bootstrap.secure; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.util.Hex; +import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServerBuilder; +import org.eclipse.leshan.server.security.EditableSecurityStore; +import org.thingsboard.server.transport.lwm2m.bootstrap.LwM2MTransportContextBootstrap; +import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode; +import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportContextServer; + +import java.math.BigInteger; +import java.security.AlgorithmParameters; +import java.security.KeyStore; +import java.security.PublicKey; +import java.security.PrivateKey; +import java.security.KeyFactory; +import java.security.GeneralSecurityException; +import java.security.KeyStoreException; +import java.security.cert.X509Certificate; +import java.security.interfaces.ECPublicKey; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPublicKeySpec; +import java.security.spec.ECPoint; +import java.security.spec.KeySpec; +import java.security.spec.ECPrivateKeySpec; +import java.util.Arrays; + +import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.NO_SEC; +import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.X509; + +@Slf4j +@Data +public class LwM2MSetSecurityStoreBootstrap { + + private KeyStore keyStore; + private PublicKey publicKey; + private PrivateKey privateKey; + private LwM2MTransportContextBootstrap contextBs; + private LwM2MTransportContextServer contextS; + private LeshanBootstrapServerBuilder builder; + EditableSecurityStore securityStore; + + public LwM2MSetSecurityStoreBootstrap(LeshanBootstrapServerBuilder builder, LwM2MTransportContextBootstrap contextBs, LwM2MTransportContextServer contextS, LwM2MSecurityMode dtlsMode) { + this.builder = builder; + this.contextBs = contextBs; + this.contextS = contextS; + /** Set securityStore with new registrationStore */ + + switch (dtlsMode) { + /** Use No_Sec only */ + case NO_SEC: + setServerWithX509Cert(NO_SEC.code); + break; + /** Use PSK/RPK */ + case PSK: + case RPK: + setRPK(); + break; + case X509: + setServerWithX509Cert(X509.code); + break; + /** Use X509_EST only */ + case X509_EST: + // TODO support sentinel pool and make pool configurable + break; + /** Use ather X509, PSK, No_Sec ?? */ + default: + break; + } + } + + private void setRPK() { + try { + /** Get Elliptic Curve Parameter spec for secp256r1 */ + AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC"); + algoParameters.init(new ECGenParameterSpec("secp256r1")); + ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class); + if (this.contextBs.getCtxBootStrap().getBootstrapPublicX() != null && !this.contextBs.getCtxBootStrap().getBootstrapPublicX().isEmpty() && this.contextBs.getCtxBootStrap().getBootstrapPublicY() != null && !this.contextBs.getCtxBootStrap().getBootstrapPublicY().isEmpty()) { + /** Get point values */ + byte[] publicX = Hex.decodeHex(this.contextBs.getCtxBootStrap().getBootstrapPublicX().toCharArray()); + byte[] publicY = Hex.decodeHex(this.contextBs.getCtxBootStrap().getBootstrapPublicY().toCharArray()); + /** Create key specs */ + KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)), + parameterSpec); + /** Get keys */ + this.publicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec); + } + if (this.contextBs.getCtxBootStrap().getBootstrapPrivateS() != null && !this.contextBs.getCtxBootStrap().getBootstrapPrivateS().isEmpty()) { + /** Get point values */ + byte[] privateS = Hex.decodeHex(this.contextBs.getCtxBootStrap().getBootstrapPrivateS().toCharArray()); + /** Create key specs */ + KeySpec privateKeySpec = new ECPrivateKeySpec(new BigInteger(privateS), parameterSpec); + /** Get keys */ + this.privateKey = KeyFactory.getInstance("EC").generatePrivate(privateKeySpec); + } + if (this.publicKey != null && this.publicKey.getEncoded().length > 0 && + this.privateKey != null && this.privateKey.getEncoded().length > 0) { + this.builder.setPublicKey(this.publicKey); + this.builder.setPrivateKey(this.privateKey); + this.contextBs.getCtxBootStrap().setBootstrapPublicKey(this.publicKey); + getParamsRPK(); + } + } catch (GeneralSecurityException | IllegalArgumentException e) { + log.error("[{}] Failed generate Server PSK/RPK", e.getMessage()); + throw new RuntimeException(e); + } + } + + private void setServerWithX509Cert(int securityModeCode) { + try { + if (this.contextS.getCtxServer().getKeyStoreValue() != null) { + KeyStore keyStoreServer = this.contextS.getCtxServer().getKeyStoreValue(); + setBuilderX509(); + X509Certificate rootCAX509Cert = (X509Certificate) keyStoreServer.getCertificate(this.contextS.getCtxServer().getRootAlias()); + if (rootCAX509Cert != null && securityModeCode == X509.code) { + X509Certificate[] trustedCertificates = new X509Certificate[1]; + trustedCertificates[0] = rootCAX509Cert; + this.builder.setTrustedCertificates(trustedCertificates); + } else { + /** by default trust all */ + this.builder.setTrustedCertificates(new X509Certificate[0]); + } + } + else { + /** by default trust all */ + this.builder.setTrustedCertificates(new X509Certificate[0]); + log.error("Unable to load X509 files for BootStrapServer"); + } + } catch (KeyStoreException ex) { + log.error("[{}] Unable to load X509 files server", ex.getMessage()); + } + + } + + private void setBuilderX509() { + /** + * For deb => KeyStorePathFile == yml or commandline: KEY_STORE_PATH_FILE + * For idea => KeyStorePathResource == common/transport/lwm2m/src/main/resources/credentials: in LwM2MTransportContextServer: credentials/serverKeyStore.jks + */ + try { + X509Certificate serverCertificate = (X509Certificate) this.contextS.getCtxServer().getKeyStoreValue().getCertificate(this.contextBs.getCtxBootStrap().getBootstrapAlias()); + this.privateKey = (PrivateKey) this.contextS.getCtxServer().getKeyStoreValue().getKey(this.contextBs.getCtxBootStrap().getBootstrapAlias(), this.contextS.getCtxServer().getKeyStorePasswordServer() == null ? null : this.contextS.getCtxServer().getKeyStorePasswordServer().toCharArray()); + if (this.privateKey != null && this.privateKey.getEncoded().length > 0) { + this.builder.setPrivateKey(this.privateKey); + } + if (serverCertificate != null) { + this.builder.setCertificateChain(new X509Certificate[]{serverCertificate}); + this.contextBs.getCtxBootStrap().setBootstrapCertificate(serverCertificate); + } + } catch (Exception ex) { + log.error("[{}] Unable to load KeyStore files server", ex.getMessage()); + } + } + + private void getParamsRPK() { + if (this.publicKey instanceof ECPublicKey) { + /** Get x coordinate */ + byte[] x = ((ECPublicKey) this.publicKey).getW().getAffineX().toByteArray(); + if (x[0] == 0) + x = Arrays.copyOfRange(x, 1, x.length); + + /** Get Y coordinate */ + byte[] y = ((ECPublicKey) this.publicKey).getW().getAffineY().toByteArray(); + if (y[0] == 0) + y = Arrays.copyOfRange(y, 1, y.length); + + /** Get Curves params */ + String params = ((ECPublicKey) this.publicKey).getParams().toString(); + log.info( + " \nBootstrap uses RPK : \n Elliptic Curve parameters : [{}] \n Public x coord : [{}] \n Public y coord : [{}] \n Public Key (Hex): [{}] \n Private Key (Hex): [{}]", + params, Hex.encodeHexString(x), Hex.encodeHexString(y), + Hex.encodeHexString(this.publicKey.getEncoded()), + Hex.encodeHexString(this.privateKey.getEncoded())); + } else { + throw new IllegalStateException("Unsupported Public Key Format (only ECPublicKey supported)."); + } + } + +// private void getParamsX509() { +// try { +// log.info("BootStrap uses X509 : \n X509 Certificate (Hex): [{}] \n Private Key (Hex): [{}]", +// Hex.encodeHexString(this.certificate.getEncoded()), +// Hex.encodeHexString(this.privateKey.getEncoded())); +// } catch (CertificateEncodingException e) { +// e.printStackTrace(); +// } +// } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java new file mode 100644 index 0000000000..db8a520266 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java @@ -0,0 +1,66 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.bootstrap.secure; + +import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.request.Identity; +import org.eclipse.leshan.server.bootstrap.BootstrapSession; +import org.eclipse.leshan.server.bootstrap.DefaultBootstrapSession; +import org.eclipse.leshan.server.bootstrap.DefaultBootstrapSessionManager; +import org.eclipse.leshan.server.security.BootstrapSecurityStore; +import org.eclipse.leshan.server.security.SecurityChecker; +import org.eclipse.leshan.server.security.SecurityInfo; + +import java.util.Arrays; +import java.util.List; + +@Slf4j +public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSessionManager { + + private BootstrapSecurityStore bsSecurityStore; + private SecurityChecker securityChecker; + + /** + * Create a {@link DefaultBootstrapSessionManager} using a default {@link SecurityChecker} to accept or refuse new + * {@link BootstrapSession}. + * + * @param bsSecurityStore the {@link BootstrapSecurityStore} used by default {@link SecurityChecker}. + */ + public LwM2mDefaultBootstrapSessionManager(BootstrapSecurityStore bsSecurityStore) { + this(bsSecurityStore, new SecurityChecker()); + } + + public LwM2mDefaultBootstrapSessionManager(BootstrapSecurityStore bsSecurityStore, SecurityChecker securityChecker) { + super(bsSecurityStore); + this.bsSecurityStore = bsSecurityStore; + this.securityChecker = securityChecker; + } + + @Override + public BootstrapSession begin(String endpoint, Identity clientIdentity) { + boolean authorized; + if (bsSecurityStore != null) { + List securityInfos = (clientIdentity.getPskIdentity() != null && !clientIdentity.getPskIdentity().isEmpty()) ? Arrays.asList(bsSecurityStore.getByIdentity(clientIdentity.getPskIdentity())) : bsSecurityStore.getAllByEndpoint(endpoint); + log.info("Bootstrap session started securityInfos: [{}]", securityInfos); + authorized = securityChecker.checkSecurityInfos(endpoint, clientIdentity, securityInfos); + } else { + authorized = true; + } + DefaultBootstrapSession session = new DefaultBootstrapSession(endpoint, clientIdentity, authorized); + log.info("Bootstrap session started : {}", session); + return session; + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LWM2MGenerationPSkRPkECC.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LWM2MGenerationPSkRPkECC.java new file mode 100644 index 0000000000..1d70ae2d83 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LWM2MGenerationPSkRPkECC.java @@ -0,0 +1,121 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.secure; + +import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.util.Hex; +import java.security.SecureRandom; +import java.security.KeyPairGenerator; +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.InvalidAlgorithmParameterException; +import java.security.interfaces.ECPublicKey; +import java.security.spec.ECGenParameterSpec; +import java.util.Arrays; + +@Slf4j +public class LWM2MGenerationPSkRPkECC { + + public LWM2MGenerationPSkRPkECC(Integer dtlsMode) { + switch (LwM2MSecurityMode.fromSecurityMode(dtlsMode)) { + case PSK: + generationPSkKey(); + break; + case RPK: + generationRPKECCKey(); + } + } + + public LWM2MGenerationPSkRPkECC() { + generationPSkKey(); + generationRPKECCKey(); + } + + private void generationPSkKey() { + /** PSK */ + int lenPSkKey = 32; + /** Start PSK + * Clients and Servers MUST support PSK keys of up to 64 bytes in length, as required by [RFC7925] + * SecureRandom object must be unpredictable, and all SecureRandom output sequences must be cryptographically strong, as described in [RFC4086] + * */ + SecureRandom randomPSK = new SecureRandom(); + byte bytesPSK[] = new byte[lenPSkKey]; + randomPSK.nextBytes(bytesPSK); + log.info("\nCreating new PSK: \n for the next start PSK -> security key: [{}]", Hex.encodeHexString(bytesPSK)); + } + + private void generationRPKECCKey() { + /** RPK */ + String algorithm = "EC"; + String provider = "SunEC"; + String nameParameterSpec = "secp256r1"; + + /** Start RPK + * Elliptic Curve parameters : [secp256r1 [NIST P-256, X9.62 prime256v1] (1.2.840.10045.3.1.7)] + * */ + KeyPairGenerator kpg = null; + try { + kpg = KeyPairGenerator.getInstance(algorithm, provider); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (NoSuchProviderException e) { + e.printStackTrace(); + } + ECGenParameterSpec ecsp = new ECGenParameterSpec(nameParameterSpec); + try { + kpg.initialize(ecsp); + } catch (InvalidAlgorithmParameterException e) { + e.printStackTrace(); + } + + KeyPair kp = kpg.genKeyPair(); + PrivateKey privKey = kp.getPrivate(); + PublicKey pubKey = kp.getPublic(); + + if (pubKey instanceof ECPublicKey) { + ECPublicKey ecPublicKey = (ECPublicKey) pubKey; + /** Get x coordinate */ + byte[] x = ecPublicKey.getW().getAffineX().toByteArray(); + if (x[0] == 0) + x = Arrays.copyOfRange(x, 1, x.length); + + /** Get Y coordinate */ + byte[] y = ecPublicKey.getW().getAffineY().toByteArray(); + if (y[0] == 0) + y = Arrays.copyOfRange(y, 1, y.length); + + /** Get Curves params */ + String privHex = Hex.encodeHexString(privKey.getEncoded()); + log.info("\nCreating new RPK for the next start... \n" + + " Elliptic Curve parameters : [{}] \n" + + " public_x : [{}] \n" + + " public_y : [{}] \n" + + " private_s : [{}] \n" + + " Public Key (Hex): [{}]\n" + + " Private Key (Hex): [{}]", + ecPublicKey.getParams().toString(), + Hex.encodeHexString(x), + Hex.encodeHexString(y), + privHex.substring(privHex.length() - 64), + Hex.encodeHexString(pubKey.getEncoded()), + Hex.encodeHexString(privKey.getEncoded())); + } + } +} + diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2MGetSecurityInfo.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2MGetSecurityInfo.java new file mode 100644 index 0000000000..ad63e21633 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2MGetSecurityInfo.java @@ -0,0 +1,170 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.secure; + +import com.google.gson.JsonObject; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.util.Hex; +import org.eclipse.leshan.core.util.SecurityUtil; +import org.eclipse.leshan.server.security.SecurityInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.DeviceProfile; +import org.thingsboard.server.common.transport.TransportServiceCallback; +import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceLwM2MCredentialsRequestMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; +import org.thingsboard.server.transport.lwm2m.bootstrap.LwM2MTransportContextBootstrap; +import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportContextServer; +import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler; +import org.thingsboard.server.transport.lwm2m.utils.TypeServer; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.PublicKey; +import java.util.Optional; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.*; + +@Slf4j +@Component("LwM2MGetSecurityInfo") +@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' ) || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") +public class LwM2MGetSecurityInfo { + + @Autowired + public LwM2MTransportContextServer contextS; + + @Autowired + public LwM2MTransportContextBootstrap contextBS; + + + public ReadResultSecurityStore getSecurityInfo(String endPoint, TypeServer keyValue) { + CountDownLatch latch = new CountDownLatch(1); + final ReadResultSecurityStore[] resultSecurityStore = new ReadResultSecurityStore[1]; + contextS.getTransportService().process(ValidateDeviceLwM2MCredentialsRequestMsg.newBuilder().setCredentialsId(endPoint).build(), + new TransportServiceCallback() { + @Override + public void onSuccess(ValidateDeviceCredentialsResponseMsg msg) { + String credentialsBody = msg.getCredentialsBody(); + resultSecurityStore[0] = putSecurityInfo(endPoint, msg.getDeviceInfo().getDeviceName(), credentialsBody, keyValue); + resultSecurityStore[0].setMsg(msg); + Optional deviceProfileOpt = LwM2MTransportHandler.decode(msg.getProfileBody().toByteArray()); + deviceProfileOpt.ifPresent(profile -> resultSecurityStore[0].setDeviceProfile(profile)); + latch.countDown(); + } + + @Override + public void onError(Throwable e) { + log.trace("[{}] Failed to process credentials PSK: {}", endPoint, e); + resultSecurityStore[0] = putSecurityInfo(endPoint, null, null, null); + latch.countDown(); + } + }); + try { + latch.await(contextS.getCtxServer().getTimeout(), TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return resultSecurityStore[0]; + } + + private ReadResultSecurityStore putSecurityInfo(String endPoint, String deviceName, String jsonStr, TypeServer keyValue) { + ReadResultSecurityStore result = new ReadResultSecurityStore(); + JsonObject objectMsg = LwM2MTransportHandler.validateJson(jsonStr); + if (objectMsg != null && !objectMsg.isJsonNull()) { + JsonObject object = (objectMsg.has(keyValue.type) && !objectMsg.get(keyValue.type).isJsonNull()) ? objectMsg.get(keyValue.type).getAsJsonObject() : null; + /** + * Only PSK + */ + String endPointPsk = (objectMsg.has("client") + && objectMsg.get("client").getAsJsonObject().has("endpoint") + && objectMsg.get("client").getAsJsonObject().get("endpoint").isJsonPrimitive()) ? objectMsg.get("client").getAsJsonObject().get("endpoint").getAsString() : null; + endPoint = (endPointPsk == null || endPointPsk.isEmpty()) ? endPoint : endPointPsk; + if (object != null && !object.isJsonNull()) { + if (keyValue.equals(TypeServer.BOOTSTRAP)) { + result.setBootstrapJsonCredential(object); + result.setEndPoint(endPoint); + } else { + LwM2MSecurityMode lwM2MSecurityMode = LwM2MSecurityMode.fromSecurityMode(object.get("securityConfigClientMode").getAsString().toLowerCase()); + switch (lwM2MSecurityMode) { + case NO_SEC: + getClientSecurityInfoNoSec(result); + break; + case PSK: + getClientSecurityInfoPSK(result, endPoint, object); + break; + case RPK: + getClientSecurityInfoRPK(result, endPoint, object); + break; + case X509: + getClientSecurityInfoX509(result, endPoint); + break; + default: + break; + } + } + } + } + return result; + } + + private void getClientSecurityInfoNoSec(ReadResultSecurityStore result) { + result.setSecurityInfo(null); + result.setSecurityMode(NO_SEC.code); + } + + private void getClientSecurityInfoPSK(ReadResultSecurityStore result, String endPoint, JsonObject object) { + /** PSK Deserialization */ + String identity = (object.has("identity") && object.get("identity").isJsonPrimitive()) ? object.get("identity").getAsString() : null; + if (identity != null && !identity.isEmpty()) { + try { + byte[] key = (object.has("key") && object.get("key").isJsonPrimitive()) ? Hex.decodeHex(object.get("key").getAsString().toCharArray()) : null; + if (key != null && key.length > 0) { + if (endPoint != null && !endPoint.isEmpty()) { + result.setSecurityInfo(SecurityInfo.newPreSharedKeyInfo(endPoint, identity, key)); + result.setSecurityMode(PSK.code); + } + } + } catch (IllegalArgumentException e) { + log.error("Missing PSK key: " + e.getMessage()); + } + } else { + log.error("Missing PSK identity"); + } + } + + private void getClientSecurityInfoRPK(ReadResultSecurityStore result, String endpoint, JsonObject object) { + try { + if (object.has("key") && object.get("key").isJsonPrimitive()) { + byte[] rpkkey = Hex.decodeHex(object.get("key").getAsString().toLowerCase().toCharArray()); + PublicKey key = SecurityUtil.publicKey.decode(rpkkey); + result.setSecurityInfo(SecurityInfo.newRawPublicKeyInfo(endpoint, key)); + result.setSecurityMode(RPK.code); + } else { + log.error("Missing RPK key"); + } + } catch (IllegalArgumentException | IOException | GeneralSecurityException e) { + log.error("RPK: Invalid security info content: " + e.getMessage()); + } + } + + private void getClientSecurityInfoX509(ReadResultSecurityStore result, String endpoint) { + result.setSecurityInfo(SecurityInfo.newX509CertInfo(endpoint)); + result.setSecurityMode(X509.code); + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2MSecurityMode.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2MSecurityMode.java new file mode 100644 index 0000000000..2e045b153c --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2MSecurityMode.java @@ -0,0 +1,58 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.secure; + +public enum LwM2MSecurityMode { + + PSK(0, "psk"), + RPK(1, "rpk"), + X509(2, "x509"), + NO_SEC(3, "no_sec"), + X509_EST(4, "x509_est"), + REDIS(7, "redis"), + DEFAULT_MODE(255, "default_mode"); + + public int code; + public String subEndpoint; + + LwM2MSecurityMode(int code, String subEndpoint) { + this.code = code; + this.subEndpoint = subEndpoint; + } + + public static LwM2MSecurityMode fromSecurityMode(long code) { + return fromSecurityMode((int) code); + } + + public static LwM2MSecurityMode fromSecurityMode(int code) { + for (LwM2MSecurityMode sm : LwM2MSecurityMode.values()) { + if (sm.code == code) { + return sm; + } + } + throw new IllegalArgumentException(String.format("Unsupported security code : %d", code)); + } + + + public static LwM2MSecurityMode fromSecurityMode(String subEndpoint) { + for (LwM2MSecurityMode sm : LwM2MSecurityMode.values()) { + if (sm.subEndpoint.equals(subEndpoint)) { + return sm; + } + } + throw new IllegalArgumentException(String.format("Unsupported security subEndpoint : %d", subEndpoint)); + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mRPkCredentials.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mRPkCredentials.java new file mode 100644 index 0000000000..44d6cfb5b1 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mRPkCredentials.java @@ -0,0 +1,84 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.secure; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.util.Hex; +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.AlgorithmParameters; +import java.security.KeyFactory; +import java.security.GeneralSecurityException; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPublicKeySpec; +import java.security.spec.KeySpec; +import java.security.spec.ECPrivateKeySpec; +import java.security.spec.ECPoint; +import java.util.List; + +@Slf4j +@Data +public class LwM2mRPkCredentials { + private PublicKey serverPublicKey; + private PrivateKey serverPrivateKey; + private X509Certificate certificate; + private List trustStore; + + /** + * create All key RPK credentials + * @param publX + * @param publY + * @param privS + */ + public LwM2mRPkCredentials(String publX, String publY, String privS) { + generatePublicKeyRPK(publX, publY, privS); + } + + private void generatePublicKeyRPK(String publX, String publY, String privS) { + try { + /**Get Elliptic Curve Parameter spec for secp256r1 */ + AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC"); + algoParameters.init(new ECGenParameterSpec("secp256r1")); + ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class); + if (publX != null && !publX.isEmpty() && publY != null && !publY.isEmpty()) { + // Get point values + byte[] publicX = Hex.decodeHex(publX.toCharArray()); + byte[] publicY = Hex.decodeHex(publY.toCharArray()); + /** Create key specs */ + KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)), + parameterSpec); + /** Get keys */ + this.serverPublicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec); + } + if (privS != null && !privS.isEmpty()) { + /** Get point values */ + byte[] privateS = Hex.decodeHex(privS.toCharArray()); + /** Create key specs */ + KeySpec privateKeySpec = new ECPrivateKeySpec(new BigInteger(privateS), parameterSpec); + /** Get keys */ + this.serverPrivateKey = KeyFactory.getInstance("EC").generatePrivate(privateKeySpec); + } + } catch (GeneralSecurityException | IllegalArgumentException e) { + log.error("[{}] Failed generate Server KeyRPK", e.getMessage()); + throw new RuntimeException(e); + } + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/ReadResultSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/ReadResultSecurityStore.java new file mode 100644 index 0000000000..28cfbfb244 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/ReadResultSecurityStore.java @@ -0,0 +1,40 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.secure; + +import com.google.gson.JsonObject; +import lombok.Builder; +import lombok.Data; +import org.eclipse.leshan.server.bootstrap.BootstrapConfig; +import org.eclipse.leshan.server.security.SecurityInfo; +import org.thingsboard.server.common.data.DeviceProfile; +import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; + +import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.DEFAULT_MODE; + +@Data +public class ReadResultSecurityStore { + private ValidateDeviceCredentialsResponseMsg msg; + private SecurityInfo securityInfo; + @Builder.Default + private int securityMode = DEFAULT_MODE.code; + + /** bootstrap */ + DeviceProfile deviceProfile; + JsonObject bootstrapJsonCredential; + String endPoint; + BootstrapConfig bootstrapConfig; +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MSessionMsgListener.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MSessionMsgListener.java new file mode 100644 index 0000000000..bf88427879 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MSessionMsgListener.java @@ -0,0 +1,88 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.server; + +import io.netty.util.concurrent.Future; +import io.netty.util.concurrent.GenericFutureListener; +import lombok.extern.slf4j.Slf4j; +import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.data.DeviceProfile; +import org.thingsboard.server.common.transport.SessionMsgListener; +import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg; +import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; +import org.thingsboard.server.gen.transport.TransportProtos.SessionCloseNotificationProto; +import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcRequestMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcResponseMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToTransportUpdateCredentialsProto; + +import java.util.Optional; + +@Slf4j +public class LwM2MSessionMsgListener implements GenericFutureListener>, SessionMsgListener { + private LwM2MTransportService service; + private TransportProtos.SessionInfoProto sessionInfo; + + LwM2MSessionMsgListener(LwM2MTransportService service, TransportProtos.SessionInfoProto sessionInfo) { + this.service = service; + this.sessionInfo = sessionInfo; + } + + @Override + public void onGetAttributesResponse(GetAttributeResponseMsg getAttributesResponse) { + log.info("[{}] attributesResponse", getAttributesResponse); + } + + @Override + public void onAttributeUpdate(AttributeUpdateNotificationMsg attributeUpdateNotification) { + this.service.onAttributeUpdate(attributeUpdateNotification, this.sessionInfo); + } + + @Override + public void onRemoteSessionCloseCommand(SessionCloseNotificationProto sessionCloseNotification) { + log.info("[{}] sessionCloseNotification", sessionCloseNotification); + } + + @Override + public void onToTransportUpdateCredentials(ToTransportUpdateCredentialsProto updateCredentials) { + this.service.onToTransportUpdateCredentials(updateCredentials); + } + + @Override + public void onDeviceProfileUpdate(TransportProtos.SessionInfoProto sessionInfo, DeviceProfile deviceProfile) { + this.service.onDeviceProfileUpdate(sessionInfo, deviceProfile); + } + + @Override + public void onDeviceUpdate(TransportProtos.SessionInfoProto sessionInfo, Device device, Optional deviceProfileOpt) { + this.service.onDeviceUpdate(sessionInfo, device, deviceProfileOpt); + } + + @Override + public void onToDeviceRpcRequest(ToDeviceRpcRequestMsg toDeviceRequest) { + log.info("[{}] toDeviceRpcRequest", toDeviceRequest); + } + + @Override + public void onToServerRpcResponse(ToServerRpcResponseMsg toServerResponse) { + log.info("[{}] toServerRpcResponse", toServerResponse); + } + + @Override + public void operationComplete(Future future) throws Exception { + log.info("[{}] operationComplete", future); + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportContextServer.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportContextServer.java new file mode 100644 index 0000000000..4bddd9a481 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportContextServer.java @@ -0,0 +1,60 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.server; +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Component; +import org.thingsboard.server.common.transport.TransportContext; +import org.thingsboard.server.common.transport.lwm2m.LwM2MTransportConfigServer; + +import javax.annotation.PostConstruct; + +@Slf4j +@Component +@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true') || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") +public class LwM2MTransportContextServer extends TransportContext { + + private LwM2MTransportConfigServer ctxServer; + + @Autowired + LwM2MTransportConfigServer lwM2MTransportConfigServer; + + @PostConstruct + public void init() { + this.ctxServer = lwM2MTransportConfigServer; + } + + public LwM2MTransportConfigServer getCtxServer () { + return this.ctxServer; + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportHandler.java new file mode 100644 index 0000000000..d922f2b1c5 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportHandler.java @@ -0,0 +1,333 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.server; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +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.model.ResourceModel; +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.LwM2mSingleResource; +import org.eclipse.leshan.core.node.LwM2mMultipleResource; +import org.eclipse.leshan.core.util.Hex; +import org.eclipse.leshan.server.californium.LeshanServer; +import org.eclipse.leshan.server.californium.LeshanServerBuilder; +import org.nustaq.serialization.FSTConfiguration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.DeviceProfile; +import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; +import org.thingsboard.server.transport.lwm2m.server.client.AttrTelemetryObserveValue; + +import javax.annotation.PostConstruct; +import java.io.File; +import java.io.IOException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Optional; +import java.util.Map; +import java.util.Arrays; +import java.util.List; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.Collections; + +@Slf4j +@Component("LwM2MTransportHandler") +@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' )|| ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") +public class LwM2MTransportHandler{ + + // We choose a default timeout a bit higher to the MAX_TRANSMIT_WAIT(62-93s) which is the time from starting to + // send a Confirmable message to the time when an acknowledgement is no longer expected. + public static final long DEFAULT_TIMEOUT = 2 * 60 * 1000l; // 2min in ms + public static final String OBSERVE_ATTRIBUTE_TELEMETRY = "observeAttr"; + public static final String KEYNAME = "keyName"; + public static final String ATTRIBUTE = "attribute"; + public static final String TELEMETRY = "telemetry"; + 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 BASE_DEVICE_API_TOPIC = "v1/devices/me"; + public static final String DEVICE_ATTRIBUTES_TOPIC = BASE_DEVICE_API_TOPIC + "/attributes"; + public static final String DEVICE_TELEMETRY_TOPIC = BASE_DEVICE_API_TOPIC + "/telemetry"; + public static final String LOG_LW2M_TELEMETRY = "logLwm2m"; + public static final String LOG_LW2M_INFO = "info"; + public static final String LOG_LW2M_ERROR = "error"; + public static final String LOG_LW2M_WARN = "warn"; + + + public static final String CLIENT_NOT_AUTHORIZED = "Client not authorized"; + + public static final String GET_TYPE_OPER_READ = "read"; + public static final String GET_TYPE_OPER_DISCOVER = "discover"; + public static final String GET_TYPE_OPER_OBSERVE = "observe"; + public static final String POST_TYPE_OPER_OBSERVE_CANCEL = "observeCancel"; + public static final String POST_TYPE_OPER_EXECUTE = "execute"; + /** + * Replaces the Object Instance or the Resource(s) with the new value provided in the “Write” operation. (see + * section 5.3.3 of the LW M2M spec). + */ + public static final String POST_TYPE_OPER_WRITE_REPLACE = "replace"; + /** + * Adds or updates Resources provided in the new value and leaves other existing Resources unchanged. (see section + * 5.3.3 of the LW M2M spec). + */ + public static final String PUT_TYPE_OPER_WRITE_UPDATE = "update"; + public static final String PUT_TYPE_OPER_WRITE_ATTRIBUTES = "wright-attributes"; + + public static final String EVENT_AWAKE = "AWAKE"; + + private static Gson gson = null; + + @Autowired + @Qualifier("LeshanServerCert") + private LeshanServer lhServerCert; + + @Autowired + @Qualifier("leshanServerNoSecPskRpk") + private LeshanServer lhServerNoSecPskRpk; + + @Autowired + private LwM2MTransportService service; + + + @PostConstruct + public void init() { + LwM2mServerListener lwM2mServerListener = new LwM2mServerListener(lhServerCert, service); + this.lhServerCert.getRegistrationService().addListener(lwM2mServerListener.registrationListener); + this.lhServerCert.getPresenceService().addListener(lwM2mServerListener.presenceListener); + this.lhServerCert.getObservationService().addListener(lwM2mServerListener.observationListener); + lwM2mServerListener = new LwM2mServerListener(lhServerNoSecPskRpk, service); + this.lhServerNoSecPskRpk.getRegistrationService().addListener(lwM2mServerListener.registrationListener); + this.lhServerNoSecPskRpk.getPresenceService().addListener(lwM2mServerListener.presenceListener); + this.lhServerNoSecPskRpk.getObservationService().addListener(lwM2mServerListener.observationListener); + } + + public static NetworkConfig getCoapConfig() { + NetworkConfig coapConfig; + File configFile = new File(NetworkConfig.DEFAULT_FILE_NAME); + if (configFile.isFile()) { + coapConfig = new NetworkConfig(); + coapConfig.load(configFile); + } else { + coapConfig = LeshanServerBuilder.createDefaultNetworkConfig(); + coapConfig.store(configFile); + } + return coapConfig; + } + + public static String getValueTypeToString (Object value, ResourceModel.Type type) { + switch (type) { + case STRING: // String + case OBJLNK: // ObjectLink + return value.toString(); + case INTEGER: // Long + return Long.toString((long) value); + case BOOLEAN: // Boolean + return Boolean.toString((Boolean) value); + case FLOAT: // Double + return Double.toString((Float)value); + case TIME: // Date + String DATE_FORMAT = "MMM d, yyyy HH:mm a"; + DateFormat formatter = new SimpleDateFormat(DATE_FORMAT); + return formatter.format(new Date((Long) Integer.toUnsignedLong(Integer.valueOf((Integer) value)))); + case OPAQUE: // byte[] value, base64 + return Hex.encodeHexString((byte[])value); + default: + 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 AttrTelemetryObserveValue getNewProfileParameters(JsonObject profilesConfigData) { + AttrTelemetryObserveValue attrTelemetryObserveValue = new AttrTelemetryObserveValue(); + attrTelemetryObserveValue.setPostKeyNameProfile(profilesConfigData.get(KEYNAME).getAsJsonObject()); + attrTelemetryObserveValue.setPostAttributeProfile(profilesConfigData.get(ATTRIBUTE).getAsJsonArray()); + attrTelemetryObserveValue.setPostTelemetryProfile(profilesConfigData.get(TELEMETRY).getAsJsonArray()); + attrTelemetryObserveValue.setPostObserveProfile(profilesConfigData.get(OBSERVE).getAsJsonArray()); + return attrTelemetryObserveValue; + } + + /** + + * @return deviceProfileBody with Observe&Attribute&Telemetry From Thingsboard + * Example: with pathResource (use only pathResource) + * property: "observeAttr" + * {"keyName": { + * "/3/0/1": "modelNumber", + * "/3/0/0": "manufacturer", + * "/3/0/2": "serialNumber" + * }, + * "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"]} + */ + public static JsonObject getObserveAttrTelemetryFromThingsboard(DeviceProfile deviceProfile) { + if (deviceProfile != null && ((Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration()).getProperties().size() > 0) { + Lwm2mDeviceProfileTransportConfiguration lwm2mDeviceProfileTransportConfiguration = (Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration(); + Object observeAttr = ((Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration()).getProperties(); + try { + ObjectMapper mapper = new ObjectMapper(); + String observeAttrStr = mapper.writeValueAsString(observeAttr); + JsonObject objectMsg = (observeAttrStr != null) ? validateJson(observeAttrStr) : null; + return (getValidateCredentialsBodyFromThingsboard(objectMsg)) ? objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject() : null; + } catch (IOException e) { + e.printStackTrace(); + } + } + return null; + } + + public static JsonObject getBootstrapParametersFromThingsboard(DeviceProfile deviceProfile) { + if (deviceProfile != null && ((Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration()).getProperties().size() > 0) { + Lwm2mDeviceProfileTransportConfiguration lwm2mDeviceProfileTransportConfiguration = (Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration(); + Object bootstrap = ((Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration()).getProperties(); + try { + ObjectMapper mapper = new ObjectMapper(); + String bootstrapStr = mapper.writeValueAsString(bootstrap); + JsonObject objectMsg = (bootstrapStr != null) ? validateJson(bootstrapStr) : null; + return (getValidateBootstrapProfileFromThingsboard(objectMsg)) ? objectMsg.get(BOOTSTRAP).getAsJsonObject() : null; + } catch (IOException e) { + e.printStackTrace(); + } + } + return null; + } + + private static boolean getValidateCredentialsBodyFromThingsboard(JsonObject objectMsg) { + return (objectMsg != null && + !objectMsg.isJsonNull() && + objectMsg.has(OBSERVE_ATTRIBUTE_TELEMETRY) && + !objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).isJsonNull() && + objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).isJsonObject() && + objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().has(KEYNAME) && + !objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(KEYNAME).isJsonNull() && + objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(KEYNAME).isJsonObject() && + objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().has(ATTRIBUTE) && + !objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(ATTRIBUTE).isJsonNull() && + objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(ATTRIBUTE).isJsonArray() && + objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().has(TELEMETRY) && + !objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(TELEMETRY).isJsonNull() && + 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()); + } + + private static boolean getValidateBootstrapProfileFromThingsboard(JsonObject objectMsg) { + return (objectMsg != null && + !objectMsg.isJsonNull() && + objectMsg.has(BOOTSTRAP) && + objectMsg.get(BOOTSTRAP).isJsonObject() && + !objectMsg.get(BOOTSTRAP).isJsonNull() && + objectMsg.get(BOOTSTRAP).getAsJsonObject().has(SERVERS) && + !objectMsg.get(BOOTSTRAP).getAsJsonObject().get(SERVERS).isJsonNull() && + objectMsg.get(BOOTSTRAP).getAsJsonObject().get(SERVERS).isJsonObject() && + objectMsg.get(BOOTSTRAP).getAsJsonObject().has(BOOTSTRAP_SERVER) && + !objectMsg.get(BOOTSTRAP).getAsJsonObject().get(BOOTSTRAP_SERVER).isJsonNull() && + objectMsg.get(BOOTSTRAP).getAsJsonObject().get(BOOTSTRAP_SERVER).isJsonObject() && + objectMsg.get(BOOTSTRAP).getAsJsonObject().has(LWM2M_SERVER) && + !objectMsg.get(BOOTSTRAP).getAsJsonObject().get(LWM2M_SERVER).isJsonNull() && + objectMsg.get(BOOTSTRAP).getAsJsonObject().get(LWM2M_SERVER).isJsonObject()); + } + + + public static JsonObject validateJson(String jsonStr) { + JsonObject object = null; + if (jsonStr != null && !jsonStr.isEmpty()) { + String jsonValidFlesh = jsonStr.replaceAll("\\\\", ""); + jsonValidFlesh = jsonValidFlesh.replaceAll("\n", ""); + jsonValidFlesh = jsonValidFlesh.replaceAll("\t", ""); + jsonValidFlesh = jsonValidFlesh.replaceAll(" ", ""); + String jsonValid = (jsonValidFlesh.substring(0, 1).equals("\"") && jsonValidFlesh.substring(jsonValidFlesh.length() - 1).equals("\"")) ? jsonValidFlesh.substring(1, jsonValidFlesh.length() - 1) : jsonValidFlesh; + try { + object = new JsonParser().parse(jsonValid).getAsJsonObject(); + } catch (JsonSyntaxException e) { + log.error("[{}] Fail validateJson [{}]", jsonStr, e.getMessage()); + } + } + return object; + } + + public static Optional decode(byte[] byteArray) { + try { + FSTConfiguration config = FSTConfiguration.createDefaultConfiguration();; + T msg = (T) config.asObject(byteArray); + return Optional.ofNullable(msg); + } catch (IllegalArgumentException e) { + log.error("Error during deserialization message, [{}]", e.getMessage()); + return Optional.empty(); + } + } + + /** + * Equals to Map for values + * @param map1 + * @param map2 + * @param + * @return + */ + public static > boolean mapsEquals(Map map1, Map map2) { + List values1 = new ArrayList(map1.values()); + List values2 = new ArrayList(map2.values()); + Collections.sort(values1); + Collections.sort(values2); + return values1.equals(values2); + } + + public static String convertCamelCase (String str) { + str = str.toLowerCase().replace("/[^a-z ]+/g", " "); + str = str.replace("/^(.)|\\s(.)/g", "$1"); + str = str.replace("/[^a-zA-Z]+/g", ""); + return str; + } + + public static String splitCamelCaseString(String s){ + LinkedList linkedListOut = new LinkedList(); + LinkedList linkedList = new LinkedList((Arrays.asList(s.split(" ")))); + linkedList.stream().forEach(str-> { + String strOut = str.replaceAll("\\W", "").replaceAll("_", "").toUpperCase(); + if (strOut.length()>1) linkedListOut.add(strOut.substring(0, 1) + strOut.substring(1).toLowerCase()); + else linkedListOut.add(strOut); + }); + linkedListOut.set(0, (linkedListOut.get(0).substring(0, 1).toLowerCase() + linkedListOut.get(0).substring(1))); + return StringUtils.join(linkedListOut, ""); + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java new file mode 100644 index 0000000000..45a85b16bb --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java @@ -0,0 +1,335 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.server; + +import lombok.extern.slf4j.Slf4j; +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.LwM2mSingleResource; +import org.eclipse.leshan.core.node.ObjectLink; +import org.eclipse.leshan.core.observation.Observation; +import org.eclipse.leshan.core.request.ContentFormat; +import org.eclipse.leshan.core.request.WriteRequest; +import org.eclipse.leshan.core.request.DiscoverRequest; +import org.eclipse.leshan.core.request.DownlinkRequest; +import org.eclipse.leshan.core.request.ObserveRequest; +import org.eclipse.leshan.core.request.CancelObservationRequest; +import org.eclipse.leshan.core.request.ReadRequest; +import org.eclipse.leshan.core.request.ExecuteRequest; +import org.eclipse.leshan.core.request.WriteAttributesRequest; +import org.eclipse.leshan.core.response.ResponseCallback; +import org.eclipse.leshan.core.response.LwM2mResponse; +import org.eclipse.leshan.core.response.ObserveResponse; +import org.eclipse.leshan.core.response.ReadResponse; +import org.eclipse.leshan.core.response.CancelObservationResponse; +import org.eclipse.leshan.core.response.DeleteResponse; +import org.eclipse.leshan.core.response.ExecuteResponse; +import org.eclipse.leshan.core.response.DiscoverResponse; +import org.eclipse.leshan.core.response.WriteAttributesResponse; +import org.eclipse.leshan.core.response.WriteResponse; +import org.eclipse.leshan.core.util.Hex; +import org.eclipse.leshan.core.util.NamedThreadFactory; +import org.eclipse.leshan.server.californium.LeshanServer; +import org.eclipse.leshan.server.registration.Registration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Service; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; + +import javax.annotation.PostConstruct; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.Iterator; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import static org.eclipse.californium.core.coap.CoAP.ResponseCode.isSuccess; +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; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.GET_TYPE_OPER_READ; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.PUT_TYPE_OPER_WRITE_ATTRIBUTES; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.PUT_TYPE_OPER_WRITE_UPDATE; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.POST_TYPE_OPER_EXECUTE; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.POST_TYPE_OPER_OBSERVE_CANCEL; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.POST_TYPE_OPER_WRITE_REPLACE; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.LOG_LW2M_ERROR; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.LOG_LW2M_INFO; + +@Slf4j +@Service("LwM2MTransportRequest") +@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' ) || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") +public class LwM2MTransportRequest { + private final ExecutorService executorService; + private static final String RESPONSE_CHANNEL = "THINGSBOARD_RESP"; + + @Autowired + LwM2MTransportService service; + + public LwM2MTransportRequest() { + executorService = Executors.newCachedThreadPool( + new NamedThreadFactory(String.format("LwM2M %s channel response", RESPONSE_CHANNEL))); + } + + + @PostConstruct + public void init() { + } + + public Collection doGetRegistrations(LeshanServer lwServer) { + Collection registrations = new ArrayList<>(); + for (Iterator iterator = lwServer.getRegistrationService().getAllRegistrations(); iterator + .hasNext(); ) { + registrations.add(iterator.next()); + } + return registrations; + } + + /** + * Device management and service enablement, including Read, Write, Execute, Discover, Create, Delete and Write-Attributes + * + * @param lwServer + * @param registration + * @param target + * @param typeOper + * @param contentFormatParam + * @param lwM2MClient + * @param observation + */ + public void sendAllRequest(LeshanServer lwServer, Registration registration, String target, String typeOper, + String contentFormatParam, LwM2MClient lwM2MClient, Observation observation, Object params, long timeoutInMs) { + ResultIds resultIds = new ResultIds(target); + if (registration != null && resultIds.getObjectId() >= 0) { + DownlinkRequest request = null; + ContentFormat contentFormat = contentFormatParam != null ? ContentFormat.fromName(contentFormatParam.toUpperCase()) : null; + ResourceModel resource = (resultIds.resourceId >= 0) ? (lwM2MClient != null) ? + lwM2MClient.getModelObjects().get(resultIds.getObjectId()).getObjectModel().resources.get(resultIds.resourceId) : null : null; + ResourceModel.Type resType = (resource == null) ? null : resource.type; + boolean resMultiple = (resource == null) ? false : resource.multiple; + timeoutInMs = timeoutInMs > 0 ? timeoutInMs : DEFAULT_TIMEOUT; + switch (typeOper) { + case GET_TYPE_OPER_READ: + request = new ReadRequest(contentFormat, target); + break; + case GET_TYPE_OPER_DISCOVER: + request = new DiscoverRequest(target); + break; + case GET_TYPE_OPER_OBSERVE: + if (resultIds.getResourceId() >= 0) { + request = new ObserveRequest(resultIds.getObjectId(), resultIds.getInstanceId(), resultIds.getResourceId()); + } else if (resultIds.getInstanceId() >= 0) { + request = new ObserveRequest(resultIds.getObjectId(), resultIds.getInstanceId()); + } else if (resultIds.getObjectId() >= 0) { + request = new ObserveRequest(resultIds.getObjectId()); + } + break; + case POST_TYPE_OPER_OBSERVE_CANCEL: + request = new CancelObservationRequest(observation); + break; + case POST_TYPE_OPER_EXECUTE: + if (params != null && !resMultiple) { + request = new ExecuteRequest(target, LwM2MTransportHandler.getValueTypeToString(params, resType)); + } else { + request = new ExecuteRequest(target); + } + break; + case POST_TYPE_OPER_WRITE_REPLACE: + // Request to write a String Single-Instance Resource using the TLV content format. + if (contentFormat.equals(ContentFormat.TLV) && !resMultiple) { + request = this.getWriteRequestSingleResource(null, resultIds.getObjectId(), resultIds.getInstanceId(), resultIds.getResourceId(), params, resType); + } + // Mode.REPLACE && Request to write a String Single-Instance Resource using the given content format (TEXT, TLV, JSON) + else if (!contentFormat.equals(ContentFormat.TLV) && !resMultiple) { + request = this.getWriteRequestSingleResource(contentFormat, resultIds.getObjectId(), resultIds.getInstanceId(), resultIds.getResourceId(), params, resType); + } + break; + case PUT_TYPE_OPER_WRITE_UPDATE: + if (resultIds.getResourceId() >= 0) { + ResourceModel resourceModel = lwServer.getModelProvider().getObjectModel(registration).getObjectModel(resultIds.getObjectId()).resources.get(resultIds.getResourceId()); + ResourceModel.Type typeRes = resourceModel.type; +// request = getWriteRequestResource(resultIds.getObjectId(), resultIds.getInstanceId(), resultIds.getResourceId(), params, typeRes); + } + 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>=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.valueOf("1"))); + Attribute[] attrs = {pmin}; + AttributeSet attrSet = new AttributeSet(attrs); + if (resultIds.getResourceId() >= 0) { + request = new WriteAttributesRequest(resultIds.getObjectId(), resultIds.getInstanceId(), resultIds.getResourceId(), attrSet); + } else if (resultIds.getInstanceId() >= 0) { + request = new WriteAttributesRequest(resultIds.getObjectId(), resultIds.getInstanceId(), attrSet); + } else if (resultIds.getObjectId() >= 0) { + request = new WriteAttributesRequest(resultIds.getObjectId(), attrSet); + } + break; + default: + } + if (request != null) sendRequest(lwServer, registration, request, lwM2MClient, timeoutInMs); + } + } + + /** + * + * @param lwServer + * @param registration + * @param request + * @param lwM2MClient + * @param timeoutInMs + */ + private void sendRequest(LeshanServer lwServer, Registration registration, DownlinkRequest request, LwM2MClient lwM2MClient, long timeoutInMs) { + lwServer.send(registration, request, timeoutInMs, (ResponseCallback) response -> { + if (isSuccess(((Response)response.getCoapResponse()).getCode())) { + this.handleResponse(registration, request.getPath().toString(), response, request, lwM2MClient); + if (request instanceof WriteRequest && ((WriteRequest) request).isReplaceRequest()) { + String msg = String.format(LOG_LW2M_INFO + " sendRequest Replace: CoapCde - %s Lwm2m code - %d name - %s Resource path - %s value - %s SendRequest to Client", + ((Response)response.getCoapResponse()).getCode(), response.getCode().getCode(), response.getCode().getName(), request.getPath().toString(), + ((LwM2mSingleResource)((WriteRequest) request).getNode()).getValue().toString()); + service.sentLogsToThingsboard(msg, registration.getId()); + log.info("[{}] - [{}] [{}] [{}] Update SendRequest", ((Response)response.getCoapResponse()).getCode(), response.getCode(), request.getPath().toString(), ((LwM2mSingleResource)((WriteRequest) request).getNode()).getValue()); + } + } + else { + String msg = String.format(LOG_LW2M_ERROR + " sendRequest: CoapCde - %s Lwm2m code - %d name - %s Resource path - %s SendRequest to Client", + ((Response)response.getCoapResponse()).getCode(), response.getCode().getCode(), response.getCode().getName(), request.getPath().toString()); + service.sentLogsToThingsboard(msg, registration.getId()); + log.error("[{}] - [{}] [{}] error SendRequest", ((Response)response.getCoapResponse()).getCode(), response.getCode(), request.getPath().toString()); + } + }, e -> { + String msg = String.format(LOG_LW2M_ERROR + " sendRequest: Resource path - %s msg error - %s SendRequest to Client", + request.getPath().toString(), e.toString()); + service.sentLogsToThingsboard(msg, registration.getId()); + log.error("[{}] - [{}] error SendRequest", request.getPath().toString(), e.toString()); + }); + } + + private WriteRequest getWriteRequestSingleResource(ContentFormat contentFormat, Integer objectId, Integer instanceId, Integer resourceId, Object value, ResourceModel.Type type) { + try { + switch (type) { + case STRING: // String + return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, value.toString()) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, value.toString()); + case INTEGER: // Long + return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, Integer.toUnsignedLong(Integer.valueOf(value.toString()))) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, Integer.toUnsignedLong(Integer.valueOf(value.toString()))); + case OBJLNK: // ObjectLink + return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, ObjectLink.fromPath(value.toString())) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, ObjectLink.fromPath(value.toString())); + case BOOLEAN: // Boolean + return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, Boolean.valueOf(value.toString())) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, Boolean.valueOf(value.toString())); + case FLOAT: // Double + return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, Double.valueOf(value.toString())) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, Double.valueOf(value.toString())); + case TIME: // Date + return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, new Date((Long) Integer.toUnsignedLong(Integer.valueOf(value.toString())))) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, new Date((Long) Integer.toUnsignedLong(Integer.valueOf(value.toString())))); + case OPAQUE: // byte[] value, base64 + return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, Hex.decodeHex(value.toString().toCharArray())) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, Hex.decodeHex(value.toString().toCharArray())); + default: + } + return null; + } catch (NumberFormatException e) { + String patn = "/" + objectId + "/" + instanceId + "/" + resourceId; + log.error("Path: [{}] type: [{}] value: [{}] errorMsg: [{}]]", patn, type, value, e.toString()); + return null; + } + } + + private void handleResponse(Registration registration, final String path, LwM2mResponse response, DownlinkRequest request, LwM2MClient lwM2MClient) { + executorService.submit(new Runnable() { + @Override + public void run() { + + try { + sendResponse(registration, path, response, request, lwM2MClient); + } catch (RuntimeException t) { + log.error("[{}] endpoint [{}] path [{}] error Unable to after send response.", registration.getEndpoint(), path, t.toString()); + } + } + }); + } + + /** + * processing a response from a client + * @param registration - + * @param path - + * @param response - + * @param lwM2MClient - + */ + private void sendResponse(Registration registration, String path, LwM2mResponse response, DownlinkRequest request, LwM2MClient lwM2MClient) { + if (response instanceof ObserveResponse) { + service.onObservationResponse(registration, path, (ReadResponse) response); + } else if (response instanceof CancelObservationResponse) { + log.info("[{}] Path [{}] CancelObservationResponse 3_Send", path, response); + } else if (response instanceof ReadResponse) { + /** + * Use only at the first start after registration + * Fill with data -> Model client + */ + if (lwM2MClient != null) { + if (lwM2MClient.getPendingRequests().size() > 0) { + lwM2MClient.onSuccessHandler(path, response); + } + } + /** + * Use after registration on request + */ + else { + service.onObservationResponse(registration, path, (ReadResponse) response); + } + } else if (response instanceof DeleteResponse) { + log.info("[{}] Path [{}] DeleteResponse 5_Send", path, response); + } else if (response instanceof DiscoverResponse) { + log.info("[{}] Path [{}] DiscoverResponse 6_Send", path, response); + } else if (response instanceof ExecuteResponse) { + log.info("[{}] Path [{}] ExecuteResponse 7_Send", path, response); + } else if (response instanceof WriteAttributesResponse) { + log.info("[{}] Path [{}] WriteAttributesResponse 8_Send", path, response); + } else if (response instanceof WriteResponse) { + log.info("[{}] Path [{}] WriteAttributesResponse 9_Send", path, response); + service.onAttributeUpdateOk(registration, path, (WriteRequest) request); + } + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerConfiguration.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerConfiguration.java new file mode 100644 index 0000000000..2725e80e2b --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerConfiguration.java @@ -0,0 +1,102 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.server; + +import lombok.extern.slf4j.Slf4j; +import org.eclipse.californium.scandium.config.DtlsConnectorConfig; +import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeDecoder; +import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeEncoder; +import org.eclipse.leshan.core.node.codec.LwM2mNodeDecoder; +import org.eclipse.leshan.server.californium.LeshanServer; +import org.eclipse.leshan.server.californium.LeshanServerBuilder; +import org.eclipse.leshan.server.model.LwM2mModelProvider; +import org.eclipse.leshan.server.model.VersionedModelProvider; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode; +import org.thingsboard.server.transport.lwm2m.server.secure.LwM2MSetSecurityStoreServer; +import org.thingsboard.server.transport.lwm2m.server.secure.LwM2mInMemorySecurityStore; +import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; +import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.X509; +import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.RPK; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.getCoapConfig; + + +@Slf4j +@ComponentScan("org.thingsboard.server.transport.lwm2m.server") +@ComponentScan("org.thingsboard.server.transport.lwm2m.utils") +@Configuration("LwM2MTransportServerConfiguration") +@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' ) || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") +public class LwM2MTransportServerConfiguration { + + @Autowired + private LwM2MTransportContextServer context; + + @Autowired + private LwM2mInMemorySecurityStore lwM2mInMemorySecurityStore; + + @Primary + @Bean(name = "LeshanServerCert") + public LeshanServer getLeshanServerCert() { + log.info("Starting LwM2M transport ServerCert... PostConstruct"); + return getLeshanServer(this.context.getCtxServer().getServerPortCert(), this.context.getCtxServer().getServerSecurePortCert(), X509); + } + + @Bean(name = "leshanServerNoSecPskRpk") + public LeshanServer getLeshanServerNoSecPskRpk() { + log.info("Starting LwM2M transport ServerNoSecPskRpk... PostConstruct"); + return getLeshanServer(this.context.getCtxServer().getServerPort(), this.context.getCtxServer().getServerSecurePort(), RPK); + } + + private LeshanServer getLeshanServer(Integer serverPort, Integer serverSecurePort, LwM2MSecurityMode dtlsMode) { + + LeshanServerBuilder builder = new LeshanServerBuilder(); + builder.setLocalAddress(this.context.getCtxServer().getServerHost(), serverPort); + builder.setLocalSecureAddress(this.context.getCtxServer().getServerSecureHost(), serverSecurePort); + builder.setEncoder(new DefaultLwM2mNodeEncoder()); + LwM2mNodeDecoder decoder = new DefaultLwM2mNodeDecoder(); + builder.setDecoder(decoder); + builder.setEncoder(new DefaultLwM2mNodeEncoder(new LwM2mValueConverterImpl())); + + /** Create CoAP Config */ + builder.setCoapConfig(getCoapConfig()); + + /** Define model provider (Create Models )*/ + LwM2mModelProvider modelProvider = new VersionedModelProvider(this.context.getCtxServer().getModelsValue()); + builder.setObjectModelProvider(modelProvider); + + /** Create DTLS Config */ + DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(); + dtlsConfig.setRecommendedCipherSuitesOnly(this.context.getCtxServer().isSupportDeprecatedCiphersEnable()); + /** Set DTLS Config */ + builder.setDtlsConfig(dtlsConfig); + + /** Use a magic converter to support bad type send by the UI. */ + builder.setEncoder(new DefaultLwM2mNodeEncoder(new LwM2mValueConverterImpl())); + + /** Create DTLS security mode + * There can be only one DTLS security mode + */ + new LwM2MSetSecurityStoreServer(builder, context, lwM2mInMemorySecurityStore, dtlsMode); + + /** Create LWM2M server */ + return builder.build(); + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerInitializer.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerInitializer.java new file mode 100644 index 0000000000..4a43407a73 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerInitializer.java @@ -0,0 +1,72 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.server; + +import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.server.californium.LeshanServer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Service; +import org.thingsboard.server.transport.lwm2m.secure.LWM2MGenerationPSkRPkECC; +import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; + +@Slf4j +@Service("LwM2MTransportServerInitializer") +@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' ) || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") +public class LwM2MTransportServerInitializer { + + @Autowired + @Qualifier("LeshanServerCert") + private LeshanServer lhServerCert; + + @Autowired + @Qualifier("leshanServerNoSecPskRpk") + private LeshanServer lhServerNoSecPskRpk; + + @Autowired + private LwM2MTransportContextServer context; + + @PostConstruct + public void init() { + if (this.context.getCtxServer().getEnableGenPskRpk()) new LWM2MGenerationPSkRPkECC(); + if (this.context.getCtxServer().isServerStartAll()) { + this.lhServerCert.start(); + this.lhServerNoSecPskRpk.start(); + } + else { + if (this.context.getCtxServer().getServerDtlsMode() == LwM2MSecurityMode.X509.code) { + this.lhServerCert.start(); + } + else { + this.lhServerNoSecPskRpk.start(); + } + } + } + + @PreDestroy + public void shutdown() { + log.info("Stopping LwM2M transport Server!"); + try { + lhServerCert.destroy(); + lhServerNoSecPskRpk.destroy(); + } finally { + } + log.info("LwM2M transport Server stopped!"); + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java new file mode 100644 index 0000000000..7ff68b928c --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java @@ -0,0 +1,999 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.server; + +import com.google.gson.*; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.model.ResourceModel; +import org.eclipse.leshan.core.node.LwM2mMultipleResource; +import org.eclipse.leshan.core.node.LwM2mObject; +import org.eclipse.leshan.core.node.LwM2mObjectInstance; +import org.eclipse.leshan.core.node.LwM2mSingleResource; +import org.eclipse.leshan.core.node.LwM2mResource; +import org.eclipse.leshan.core.node.LwM2mPath; +import org.eclipse.leshan.core.observation.Observation; +import org.eclipse.leshan.core.request.ContentFormat; +import org.eclipse.leshan.core.request.WriteRequest; +import org.eclipse.leshan.core.response.ReadResponse; +import org.eclipse.leshan.core.util.Hex; +import org.eclipse.leshan.server.californium.LeshanServer; +import org.eclipse.leshan.server.registration.Registration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.data.DeviceProfile; +import org.thingsboard.server.common.transport.TransportService; +import org.thingsboard.server.common.transport.TransportServiceCallback; +import org.thingsboard.server.common.transport.adaptor.AdaptorException; +import org.thingsboard.server.common.transport.adaptor.JsonConverter; +import org.thingsboard.server.common.transport.service.DefaultTransportService; +import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.gen.transport.TransportProtos.ToTransportUpdateCredentialsProto; +import org.thingsboard.server.gen.transport.TransportProtos.SessionEvent; +import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; +import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; +import org.thingsboard.server.gen.transport.TransportProtos.PostTelemetryMsg; +import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg; +import org.thingsboard.server.transport.lwm2m.server.adaptors.LwM2MJsonAdaptor; +import org.thingsboard.server.transport.lwm2m.server.client.AttrTelemetryObserveValue; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.ModelObject; +import org.thingsboard.server.transport.lwm2m.server.client.ResultsAnalyzerParameters; +import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue; +import org.thingsboard.server.transport.lwm2m.server.secure.LwM2mInMemorySecurityStore; + +import javax.annotation.PostConstruct; +import java.util.Collection; +import java.util.UUID; +import java.util.Random; +import java.util.Map; +import java.util.HashMap; +import java.util.Arrays; +import java.util.Set; +import java.util.HashSet; +import java.util.NoSuchElementException; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.*; + +@Slf4j +@Service("LwM2MTransportService") +@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' ) || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") +public class LwM2MTransportService { + + @Autowired + private LwM2MJsonAdaptor adaptor; + + @Autowired + private TransportService transportService; + + @Autowired + public LwM2MTransportContextServer context; + + @Autowired + private LwM2MTransportRequest lwM2MTransportRequest; + + @Autowired + LwM2mInMemorySecurityStore lwM2mInMemorySecurityStore; + + + @PostConstruct + public void init() { + context.getScheduler().scheduleAtFixedRate(() -> checkInactivityAndReportActivity(), new Random().nextInt((int) context.getCtxServer().getSessionReportTimeout()), context.getCtxServer().getSessionReportTimeout(), TimeUnit.MILLISECONDS); + } + + /** + * Start registration device + * Create session: Map, LwM2MClient> + * 1. replaceNewRegistration -> (solving the problem of incorrect termination of the previous session with this endpoint) + * 1.1 When we initialize the registration, we register the session by endpoint. + * 1.2 If the server has incomplete requests (canceling the registration of the previous session), + * delete the previous session only by the previous registration.getId + * 1.2 Add Model (Entity) for client (from registration & observe) by registration.getId + * 1.2 Remove from sessions Model by enpPoint + * Next -> Create new LwM2MClient for current session -> setModelClient... + * + * @param lwServer - LeshanServer + * @param registration - Registration LwM2M Client + * @param previousObsersations - may be null + */ + public void onRegistered(LeshanServer lwServer, Registration registration, Collection previousObsersations) { + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getlwM2MClient(lwServer, registration); + if (lwM2MClient != null) { + lwM2MClient.setLwM2MTransportService(this); + lwM2MClient.setLwM2MTransportService(this); + lwM2MClient.setSessionUuid(UUID.randomUUID()); + this.setLwM2MClient(lwServer, registration, lwM2MClient); + SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration.getId()); + if (sessionInfo != null) { + lwM2MClient.setDeviceUuid(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB())); + lwM2MClient.setProfileUuid(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); + lwM2MClient.setDeviceName(sessionInfo.getDeviceName()); + lwM2MClient.setDeviceProfileName(sessionInfo.getDeviceType()); + transportService.registerAsyncSession(sessionInfo, new LwM2MSessionMsgListener(this, sessionInfo)); + transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN), null); + transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), null); + this.sentLogsToThingsboard(LOG_LW2M_INFO + ": Client registration", registration.getId()); + } else { + log.error("Client: [{}] onRegistered [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), sessionInfo); + } + } else { + log.error("Client: [{}] onRegistered [{}] name [{}] lwM2MClient ", registration.getId(), registration.getEndpoint(), lwM2MClient); + } + } + + /** + * @param lwServer - LeshanServer + * @param registration - Registration LwM2M Client + */ + public void updatedReg(LeshanServer lwServer, Registration registration) { + SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration.getId()); + if (sessionInfo != null) { + log.info("Client: [{}] updatedReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType()); + } else { + log.error("Client: [{}] updatedReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), sessionInfo); + } + } + + /** + * @param registration - Registration LwM2M Client + * @param observations - All paths observations before unReg + * !!! Warn: if have not finishing unReg, then this operation will be finished on next Client`s connect + */ + public void unReg(Registration registration, Collection observations) { + this.sentLogsToThingsboard(LOG_LW2M_INFO + ": Client unRegistration", registration.getId()); + this.closeClientSession(registration); + } + + private void closeClientSession(Registration registration) { + SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration.getId()); + if (sessionInfo != null) { + transportService.deregisterSession(sessionInfo); + this.doCloseSession(sessionInfo); + lwM2mInMemorySecurityStore.delRemoveSessionAndListener(registration.getId()); + if (lwM2mInMemorySecurityStore.getProfiles().size() > 0) { + this.syncSessionsAndProfiles(); + } + log.info("Client: [{}] unReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType()); + } else { + log.error("Client: [{}] unReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), sessionInfo); + } + } + + public void onSleepingDev(Registration registration) { + log.info("[{}] [{}] Received endpoint Sleeping version event", registration.getId(), registration.getEndpoint()); + //TODO: associate endpointId with device information. + } + + /** + * Those methods are called by the protocol stage thread pool, this means that execution MUST be done in a short delay, + * * if you need to do long time processing use a dedicated thread pool. + * + * @param registration + */ + + public void onAwakeDev(Registration registration) { + log.info("[{}] [{}] Received endpoint Awake version event", registration.getId(), registration.getEndpoint()); + //TODO: associate endpointId with device information. + } + + /** + * This method is used to sync with sessions + * Removes a profile if not used in sessions + */ + private void syncSessionsAndProfiles() { + Map profilesClone = lwM2mInMemorySecurityStore.getProfiles().entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + profilesClone.forEach((k, v) -> { + String registrationId = lwM2mInMemorySecurityStore.getSessions().entrySet() + .stream() + .filter(e -> e.getValue().getProfileUuid().equals(k)) + .findFirst() + .map(Map.Entry::getKey) // return the key of the matching entry if found + .orElse(""); + if (registrationId.isEmpty()) { + lwM2mInMemorySecurityStore.getProfiles().remove(k); + } + }); + } + + /** + * Create new LwM2MClient for current session -> setModelClient... + * #1 Add all ObjectLinks (instance) to control the process of executing requests to the client + * to get the client model with current values + * #2 Get the client model with current values. Analyze the response in -> lwM2MTransportRequest.sendResponse + * + * @param lwServer - LeshanServer + * @param registration - Registration LwM2M Client + * @param lwM2MClient - object with All parameters off client + */ + private void setLwM2MClient(LeshanServer lwServer, Registration registration, LwM2MClient lwM2MClient) { + // #1 + Arrays.stream(registration.getObjectLinks()).forEach(url -> { + ResultIds pathIds = new ResultIds(url.getUrl()); + if (pathIds.instanceId > -1 && pathIds.resourceId == -1) { + lwM2MClient.getPendingRequests().add(url.getUrl()); + } + }); + // #2 + Arrays.stream(registration.getObjectLinks()).forEach(url -> { + ResultIds pathIds = new ResultIds(url.getUrl()); + if (pathIds.instanceId > -1 && pathIds.resourceId == -1) { + lwM2MTransportRequest.sendAllRequest(lwServer, registration, url.getUrl(), GET_TYPE_OPER_READ, + ContentFormat.TLV.getName(), lwM2MClient, null, null, this.context.getCtxServer().getTimeout()); + } + }); + } + + /** + * @param registrationId - Id of Registration LwM2M Client + * @return - sessionInfo after access connect client + */ + private SessionInfoProto getValidateSessionInfo(String registrationId) { + SessionInfoProto sessionInfo = null; + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getlwM2MClient(registrationId); + if (lwM2MClient != null) { + ValidateDeviceCredentialsResponseMsg msg = lwM2MClient.getCredentialsResponse(); + if (msg == null || msg.getDeviceInfo() == null) { + log.error("[{}] [{}]", lwM2MClient.getEndPoint(), CLIENT_NOT_AUTHORIZED); + this.closeClientSession(lwM2MClient.getRegistration()); + } else { + sessionInfo = SessionInfoProto.newBuilder() + .setNodeId(this.context.getNodeId()) + .setSessionIdMSB(lwM2MClient.getSessionUuid().getMostSignificantBits()) + .setSessionIdLSB(lwM2MClient.getSessionUuid().getLeastSignificantBits()) + .setDeviceIdMSB(msg.getDeviceInfo().getDeviceIdMSB()) + .setDeviceIdLSB(msg.getDeviceInfo().getDeviceIdLSB()) + .setTenantIdMSB(msg.getDeviceInfo().getTenantIdMSB()) + .setTenantIdLSB(msg.getDeviceInfo().getTenantIdLSB()) + .setDeviceName(msg.getDeviceInfo().getDeviceName()) + .setDeviceType(msg.getDeviceInfo().getDeviceType()) + .setDeviceProfileIdLSB(msg.getDeviceInfo().getDeviceProfileIdLSB()) + .setDeviceProfileIdMSB(msg.getDeviceInfo().getDeviceProfileIdMSB()) + .build(); + } + } + return sessionInfo; + } + + /** + * Add attribute/telemetry information from Client and credentials/Profile to client model and start observe + * !!! if the resource has an observation, but no telemetry or attribute - the observation will not use + * #1 Client`s starting info to send to thingsboard + * #2 Sending Attribute Telemetry with value to thingsboard only once at the start of the connection + * #3 Start observe + * + * @param lwServer - LeshanServer + * @param registration - Registration LwM2M Client + */ + + public void updatesAndSentModelParameter(LeshanServer lwServer, Registration registration) { + // #1 +// this.setParametersToModelClient(registration, modelClient, deviceProfile); + // #2 + this.updateAttrTelemetry(registration, true, null); + // #3 + this.onSentObserveToClient(lwServer, registration); + } + + + /** + * Sent Attribute and Telemetry to Thingsboard + * #1 - get AttrName/TelemetryName with value: + * #1.1 from Client + * #1.2 from LwM2MClient: + * -- resourceId == path from AttrTelemetryObserveValue.postAttributeProfile/postTelemetryProfile/postObserveProfile + * -- AttrName/TelemetryName == resourceName from ModelObject.objectModel, value from ModelObject.instance.resource(resourceId) + * #2 - set Attribute/Telemetry + * + * @param registration - Registration LwM2M Client + */ + private void updateAttrTelemetry(Registration registration, boolean start, Set paths) { + JsonObject attributes = new JsonObject(); + JsonObject telemetrys = new JsonObject(); + if (start) { + // #1.1 + JsonObject attributeClient = this.getAttributeClient(registration); + if (attributeClient != null) { + attributeClient.entrySet().forEach(p -> { + attributes.add(p.getKey(), p.getValue()); + }); + } + } + // #1.2 + CountDownLatch cancelLatch = new CountDownLatch(1); + this.getParametersFromProfile(attributes, telemetrys, registration, paths); + cancelLatch.countDown(); + try { + cancelLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + log.error("[{}] updateAttrTelemetry", e.toString()); + } + if (attributes.getAsJsonObject().entrySet().size() > 0) + this.updateParametersOnThingsboard(attributes, DEVICE_ATTRIBUTES_TOPIC, registration.getId()); + if (telemetrys.getAsJsonObject().entrySet().size() > 0) + this.updateParametersOnThingsboard(telemetrys, DEVICE_TELEMETRY_TOPIC, registration.getId()); + } + + /** + * get AttrName/TelemetryName with value from Client + * + * @param registration - + * @return - JsonObject, format: {name: value}} + */ + private JsonObject getAttributeClient(Registration registration) { + if (registration.getAdditionalRegistrationAttributes().size() > 0) { + JsonObject resNameValues = new JsonObject(); + registration.getAdditionalRegistrationAttributes().entrySet().forEach(entry -> { + resNameValues.addProperty(entry.getKey(), entry.getValue()); + }); + return resNameValues; + } + return null; + } + + /** + * @param attributes - new JsonObject + * @param telemetry - new JsonObject + * @param registration - Registration LwM2M Client + * result: add to JsonObject those resources to which the user is subscribed and they have a value + * if path==null add All resources else only one + * (attributes/telemetry): new {name(Attr/Telemetry):value} + */ + private void getParametersFromProfile(JsonObject attributes, JsonObject telemetry, Registration registration, Set path) { + AttrTelemetryObserveValue attrTelemetryObserveValue = lwM2mInMemorySecurityStore.getProfiles().get(lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getProfileUuid()); + attrTelemetryObserveValue.getPostAttributeProfile().forEach(p -> { + ResultIds pathIds = new ResultIds(p.getAsString().toString()); + if (pathIds.getResourceId() > -1) { + if (path == null || path.contains(p.getAsString())) { + this.addParameters(pathIds, p.getAsString().toString(), attributes, registration); + } + } + }); + attrTelemetryObserveValue.getPostTelemetryProfile().forEach(p -> { + ResultIds pathIds = new ResultIds(p.getAsString().toString()); + if (pathIds.getResourceId() > -1) { + if (path == null || path.contains(p.getAsString())) { + this.addParameters(pathIds, p.getAsString().toString(), telemetry, registration); + } + } + }); + } + + /** + * @param pathIds - path resource + * @param parameters - JsonObject attributes/telemetry + * @param registration - Registration LwM2M Client + */ + private void addParameters(ResultIds pathIds, String path, JsonObject parameters, Registration registration) { + ModelObject modelObject = lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getModelObjects().get(pathIds.getObjectId()); + JsonObject names = lwM2mInMemorySecurityStore.getProfiles().get(lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getProfileUuid()).getPostKeyNameProfile(); + String resName = String.valueOf(names.get(path)); + if (modelObject != null && resName != null && !resName.isEmpty()) { + String resValue = this.getResourceValue(modelObject, pathIds); + if (resValue != null) { + parameters.addProperty(resName, resValue); + } + } + } + + /** + * @param modelObject - ModelObject of Client + * @param pathIds - path resource + * @return - value of Resource or null + */ + private String getResourceValue(ModelObject modelObject, ResultIds pathIds) { + String resValue = null; + if (modelObject.getInstances().get(pathIds.getInstanceId()) != null) { + LwM2mObjectInstance instance = modelObject.getInstances().get(pathIds.getInstanceId()); + if (instance.getResource(pathIds.getResourceId()) != null) { + resValue = instance.getResource(pathIds.getResourceId()).getType() == OPAQUE ? + Hex.encodeHexString((byte[]) instance.getResource(pathIds.getResourceId()).getValue()).toLowerCase() : + (instance.getResource(pathIds.getResourceId()).isMultiInstances()) ? + instance.getResource(pathIds.getResourceId()).getValues().toString() : + instance.getResource(pathIds.getResourceId()).getValue().toString(); + } + } + return resValue; + } + + /** + * Prepare Sent to Thigsboard callback - Attribute or Telemetry + * + * @param msg - JsonArray: [{name: value}] + * @param topicName - Api Attribute or Telemetry + * @param registrationId - Id of Registration LwM2M Client + */ + public void updateParametersOnThingsboard(JsonElement msg, String topicName, String registrationId) { + SessionInfoProto sessionInfo = this.getValidateSessionInfo(registrationId); + if (sessionInfo != null) { + try { + if (topicName.equals(LwM2MTransportHandler.DEVICE_ATTRIBUTES_TOPIC)) { + PostAttributeMsg postAttributeMsg = adaptor.convertToPostAttributes(msg); + TransportServiceCallback call = this.getPubAckCallbackSentAttrTelemetry(-1, postAttributeMsg); + transportService.process(sessionInfo, postAttributeMsg, call); + } else if (topicName.equals(LwM2MTransportHandler.DEVICE_TELEMETRY_TOPIC)) { + PostTelemetryMsg postTelemetryMsg = adaptor.convertToPostTelemetry(msg); + TransportServiceCallback call = this.getPubAckCallbackSentAttrTelemetry(-1, postTelemetryMsg); + transportService.process(sessionInfo, postTelemetryMsg, this.getPubAckCallbackSentAttrTelemetry(-1, call)); + } + } catch (AdaptorException e) { + log.error("[{}] Failed to process publish msg [{}]", topicName, e); + log.info("[{}] Closing current session due to invalid publish", topicName); + } + } else { + log.error("Client: [{}] updateParametersOnThingsboard [{}] sessionInfo ", registrationId, sessionInfo); + } + } + + /** + * Sent to Thingsboard Attribute || Telemetry + * + * @param msgId - always == -1 + * @param msg - JsonObject: [{name: value}] + * @return - dummy + */ + private TransportServiceCallback getPubAckCallbackSentAttrTelemetry(final int msgId, final T msg) { + return new TransportServiceCallback() { + @Override + public void onSuccess(Void dummy) { + log.trace("Success to publish msg: {}, dummy: {}", msg, dummy); + } + + @Override + public void onError(Throwable e) { + log.trace("[{}] Failed to publish msg: {}", msg, e); + } + }; + } + + + /** + * Start observe + * #1 - Analyze: + * #1.1 path in observe == (attribute or telemetry) + * #1.2 recourseValue notNull + * #2 Analyze after sent request (response): + * #2.1 First: lwM2MTransportRequest.sendResponse -> ObservationListener.newObservation + * #2.2 Next: ObservationListener.onResponse * + * + * @param lwServer - LeshanServer + * @param registration - Registration LwM2M Client + */ + private void onSentObserveToClient(LeshanServer lwServer, Registration registration) { + if (lwServer.getObservationService().getObservations(registration).size() > 0) { + this.setCancelObservations(lwServer, registration); + } + UUID profileUUid = lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getProfileUuid(); + AttrTelemetryObserveValue attrTelemetryObserveValue = lwM2mInMemorySecurityStore.getProfiles().get(profileUUid); + attrTelemetryObserveValue.getPostObserveProfile().forEach(p -> { + // #1.1 + String target = (getValidateObserve(attrTelemetryObserveValue.getPostAttributeProfile(), p.getAsString().toString())) ? + p.getAsString().toString() : (getValidateObserve(attrTelemetryObserveValue.getPostTelemetryProfile(), p.getAsString().toString())) ? + p.getAsString().toString() : null; + if (target != null) { + // #1.2 + ResultIds pathIds = new ResultIds(target); + ModelObject modelObject = lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getModelObjects().get(pathIds.getObjectId()); + // #2 + if (modelObject != null) { + if (getResourceValue(modelObject, pathIds) != null) { + lwM2MTransportRequest.sendAllRequest(lwServer, registration, target, GET_TYPE_OPER_OBSERVE, + null, null, null, null, this.context.getCtxServer().getTimeout()); + } + } + } + }); + } + + public void setCancelObservations(LeshanServer lwServer, Registration registration) { + if (registration != null) { + Set observations = lwServer.getObservationService().getObservations(registration); + observations.forEach(observation -> { + this.setCancelObservationRecourse(lwServer, registration, observation.getPath().toString()); + }); + } + } + + /** + * lwM2MTransportRequest.sendAllRequest(lwServer, registration, path, POST_TYPE_OPER_OBSERVE_CANCEL, null, null, null, null, context.getTimeout()); + * At server side this will not remove the observation from the observation store, to do it you need to use + * {@code ObservationService#cancelObservation()} + */ + public void setCancelObservationRecourse(LeshanServer lwServer, Registration registration, String path) { + CountDownLatch cancelLatch = new CountDownLatch(1); + lwServer.getObservationService().cancelObservations(registration, path); + cancelLatch.countDown(); + try { + cancelLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + } + } + + /** + * @param parameters - JsonArray postAttributeProfile/postTelemetryProfile + * @param path - recourse from postObserveProfile + * @return rez - true if path observe is in attribute/telemetry + */ + private boolean getValidateObserve(JsonElement parameters, String path) { + AtomicBoolean rez = new AtomicBoolean(false); + if (parameters.isJsonArray()) { + parameters.getAsJsonArray().forEach(p -> { + if (p.getAsString().toString().equals(path)) rez.set(true); + } + ); + } else if (parameters.isJsonObject()) { + rez.set((parameters.getAsJsonObject().entrySet()).stream().map(json -> json.toString()) + .filter(path::equals).findAny().orElse(null) != null); + } + return rez.get(); + } + + /** + * Sending observe value to thingsboard from ObservationListener.onResponse: object, instance, SingleResource or MultipleResource + * + * @param registration - Registration LwM2M Client + * @param path - observe + * @param response - observe + */ + @SneakyThrows + public void onObservationResponse(Registration registration, String path, ReadResponse response) { + if (response.getContent() != null) { + if (response.getContent() instanceof LwM2mObject) { + LwM2mObject content = (LwM2mObject) response.getContent(); + String target = "/" + content.getId(); + } else if (response.getContent() instanceof LwM2mObjectInstance) { + LwM2mObjectInstance content = (LwM2mObjectInstance) response.getContent(); + } else if (response.getContent() instanceof LwM2mSingleResource) { + LwM2mSingleResource content = (LwM2mSingleResource) response.getContent(); + this.onObservationSetResourcesValue(registration, content.getValue(), null, path); + } else if (response.getContent() instanceof LwM2mMultipleResource) { + LwM2mSingleResource content = (LwM2mSingleResource) response.getContent(); + this.onObservationSetResourcesValue(registration, null, content.getValues(), path); + } + } + } + + /** + * Sending observe value of resources to thingsboard + * #1 Return old Resource from ModelObject + * #2 Create new Resource with value from observation + * #3 Create new Resources from old Resources + * #4 Update new Resources (replace old Resource on new Resource) + * #5 Remove old Instance from modelClient + * #6 Create new Instance with new Resources values + * #7 Update modelClient.getModelObjects(idObject) (replace old Instance on new Instance) + * + * @param registration - Registration LwM2M Client + * @param value - LwM2mSingleResource response.getContent() + * @param values - LwM2mSingleResource response.getContent() + * @param path - resource + */ + private void onObservationSetResourcesValue(Registration registration, Object value, Map values, String path) { + ResultIds resultIds = new ResultIds(path); + // #1 + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getlwM2MClient(registration.getId()); + ModelObject modelObject = lwM2MClient.getModelObjects().get(resultIds.getObjectId()); + Map instancesModelObject = modelObject.getInstances(); + LwM2mObjectInstance instanceOld = (instancesModelObject.get(resultIds.instanceId) != null) ? instancesModelObject.get(resultIds.instanceId) : null; + Map resourcesOld = (instanceOld != null) ? instanceOld.getResources() : null; + LwM2mResource resourceOld = (resourcesOld != null && resourcesOld.get(resultIds.getResourceId()) != null) ? resourcesOld.get(resultIds.getResourceId()) : null; + // #2 + LwM2mResource resourceNew; + if (resourceOld.isMultiInstances()) { + resourceNew = LwM2mMultipleResource.newResource(resultIds.getResourceId(), values, resourceOld.getType()); + } else { + resourceNew = LwM2mSingleResource.newResource(resultIds.getResourceId(), value, resourceOld.getType()); + } + //#3 + Map resourcesNew = new HashMap<>(resourcesOld); + // #4 + resourcesNew.remove(resourceOld); + // #5 + resourcesNew.put(resultIds.getResourceId(), resourceNew); + // #6 + LwM2mObjectInstance instanceNew = new LwM2mObjectInstance(resultIds.instanceId, resourcesNew.values()); + // #7 + CountDownLatch respLatch = new CountDownLatch(1); + lwM2MClient.getModelObjects().get(resultIds.getObjectId()).removeInstance(resultIds.instanceId); + instancesModelObject.put(resultIds.instanceId, instanceNew); + respLatch.countDown(); + try { + respLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); + } catch (InterruptedException ex) { + } + Set paths = new HashSet(); + paths.add(path); + this.updateAttrTelemetry(registration, false, paths); + } + + /** + * @param updateCredentials - Credentials include config only security Client (without config attr/telemetry...) + * config attr/telemetry... in profile + */ + public void onToTransportUpdateCredentials(ToTransportUpdateCredentialsProto updateCredentials) { + log.info("[{}] idList [{}] valueList updateCredentials", updateCredentials.getCredentialsIdList(), updateCredentials.getCredentialsValueList()); + } + + /** + * Update - sent request in change value resources in Client (path to resources from profile by keyName) + * Only fo resources W + * Delete - nothing + * + * @param msg - + * @param sessionInfo - + */ + public void onAttributeUpdate(TransportProtos.AttributeUpdateNotificationMsg msg, SessionInfoProto sessionInfo) { + if (msg.getSharedUpdatedCount() > 0) { + JsonElement el = JsonConverter.toJson(msg); + el.getAsJsonObject().entrySet().forEach(de -> { + String profilePath = lwM2mInMemorySecurityStore.getProfiles().get(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())) + .getPostKeyNameProfile().getAsJsonObject().entrySet().stream() + .filter(e -> e.getValue().getAsString().equals(de.getKey())).findFirst().map(Map.Entry::getKey) + .orElse(""); + String path = !profilePath.isEmpty() ? profilePath : this.getPathAttributeUpdate(sessionInfo, de.getKey()); + if (path != null) { + ResultIds resultIds = new ResultIds(path); + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getSession(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())).entrySet().iterator().next().getValue(); + ResourceModel.Operations operations = lwM2MClient.getModelObjects().get(resultIds.getObjectId()).getObjectModel().resources.get(resultIds.getResourceId()).operations; + String value = ((JsonPrimitive) de.getValue()).getAsString(); + if (operations.isWritable()) { + lwM2MTransportRequest.sendAllRequest(lwM2MClient.getLwServer(), lwM2MClient.getRegistration(), path, POST_TYPE_OPER_WRITE_REPLACE, + ContentFormat.TLV.getName(), lwM2MClient, null, value, this.context.getCtxServer().getTimeout()); + log.info("[{}] path onAttributeUpdate", path); + } + else { + log.error(LOG_LW2M_ERROR + ": Resource path - [{}] value - [{}] is not Writable and cannot be updated", path, value); + String logMsg = String.format(LOG_LW2M_ERROR + " attributeUpdate: Resource path - %s value - %s is not Writable and cannot be updated", path, value); + this.sentLogsToThingsboard(logMsg, lwM2MClient.getRegistration().getId()); + } + } + }); + } else if (msg.getSharedDeletedCount() > 0) { + log.info("[{}] delete [{}] onAttributeUpdate", msg.getSharedDeletedList(), sessionInfo); + } + } + + private String getPathAttributeUpdate(SessionInfoProto sessionInfo, String keyName) { + try { + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getSession(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())).entrySet().iterator().next().getValue(); + Predicate> predicateRes = res -> keyName.equals(splitCamelCaseString(res.getValue().name)); + Predicate> predicateObj = (obj -> { + return obj.getValue().getObjectModel().resources.entrySet().stream().filter(predicateRes).findFirst().isPresent(); + }); + Stream> objectStream = lwM2MClient.getModelObjects().entrySet().stream().filter(predicateObj); + Predicate> predicateResFinal = (objectStream.count() > 0) ? predicateRes : res -> keyName.equals(res.getValue().name); + Predicate> predicateObjFinal = (obj -> { + return obj.getValue().getObjectModel().resources.entrySet().stream().filter(predicateResFinal).findFirst().isPresent(); + }); + Map.Entry object = lwM2MClient.getModelObjects().entrySet().stream().filter(predicateObjFinal).findFirst().get(); + ModelObject modelObject = object.getValue(); + LwM2mObjectInstance instance = modelObject.getInstances().entrySet().stream().findFirst().get().getValue(); + ResourceModel resource = modelObject.getObjectModel().resources.entrySet().stream().filter(predicateResFinal).findFirst().get().getValue(); + return new LwM2mPath(object.getKey(), instance.getId(), resource.id).toString(); + } catch (NoSuchElementException e) { + log.error("[{}] keyName [{}]", keyName, e.toString()); + return null; + } + } + + public void onAttributeUpdateOk(Registration registration, String path, WriteRequest request) { + ResultIds resultIds = new ResultIds(path); + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getlwM2MClient(registration.getId()); + LwM2mResource resource = lwM2MClient.getModelObjects().get(resultIds.getObjectId()).getInstances().get(resultIds.getInstanceId()).getResource(resultIds.getResourceId()); + if (resource.isMultiInstances()) { + this.onObservationSetResourcesValue(registration, null, ((LwM2mSingleResource) request.getNode()).getValues(), path); + } else { + this.onObservationSetResourcesValue(registration, ((LwM2mSingleResource) request.getNode()).getValue(), null, path); + } + } + + /** + * @param sessionInfo - + * @param deviceProfile - + */ + public void onDeviceProfileUpdate(TransportProtos.SessionInfoProto sessionInfo, DeviceProfile deviceProfile) { + String registrationId = lwM2mInMemorySecurityStore.getSessions().entrySet() + .stream() + .filter(e -> e.getValue().getDeviceUuid().equals(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB()))) + .findFirst() + .map(Map.Entry::getKey) + .orElse(""); + if (!registrationId.isEmpty()) { + this.onDeviceUpdateChangeProfile(registrationId, deviceProfile); + } + } + + /** + * @param sessionInfo - + * @param device - + * @param deviceProfileOpt - + */ + public void onDeviceUpdate(TransportProtos.SessionInfoProto sessionInfo, Device device, Optional deviceProfileOpt) { + Optional registrationIdOpt = lwM2mInMemorySecurityStore.getSessions().entrySet().stream() + .filter(e -> device.getUuidId().equals(e.getValue().getDeviceUuid())) + .map(Map.Entry::getKey) + .findFirst(); + registrationIdOpt.ifPresent(registrationId -> this.onDeviceUpdateLwM2MClient(registrationId, device, deviceProfileOpt)); + } + + /** + * Update parameters device in LwM2MClient + * If new deviceProfile != old deviceProfile => update deviceProfile + * + * @param registrationId - + * @param device - + */ + private void onDeviceUpdateLwM2MClient(String registrationId, Device device, Optional deviceProfileOpt) { + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getSessions().get(registrationId); + lwM2MClient.setDeviceName(device.getName()); + if (!lwM2MClient.getProfileUuid().equals(device.getDeviceProfileId().getId())) { + deviceProfileOpt.ifPresent(deviceProfile -> this.onDeviceUpdateChangeProfile(registrationId, deviceProfile)); + } + } + + /** + * #1 Read new, old Value (Attribute, Telemetry, Observe, KeyName) + * #2 Update in lwM2MClient: ...Profile + * #3 Equivalence test: old <> new Value (Attribute, Telemetry, Observe, KeyName) + * #3.1 Attribute isChange (add&del) + * #3.2 Telemetry isChange (add&del) + * #3.3 KeyName isChange (add) + * #4 update + * #4.1 add If #3 isChange, then analyze and update Value in Transport form Client and sent Value ti thingsboard + * #4.2 del + * -- if add attributes includes del telemetry - result del for observe + * #5 + * #5.1 Observe isChange (add&del) + * #5.2 Observe.add + * -- path Attr/Telemetry includes newObserve and does not include oldObserve: sent Request observe to Client + * #5.3 Observe.del + * -- different between newObserve and oldObserve: sent Request cancel observe to client + * + * @param registrationId - + * @param deviceProfile - + */ + public void onDeviceUpdateChangeProfile(String registrationId, DeviceProfile deviceProfile) { + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getlwM2MClient(registrationId); + AttrTelemetryObserveValue attrTelemetryObserveValueOld = lwM2mInMemorySecurityStore.getProfiles().get(lwM2MClient.getProfileUuid()); + if (lwM2mInMemorySecurityStore.addUpdateProfileParameters(deviceProfile)) { + LeshanServer lwServer = lwM2MClient.getLwServer(); + Registration registration = lwM2mInMemorySecurityStore.getByRegistration(registrationId); + // #1 + JsonArray attributeOld = attrTelemetryObserveValueOld.getPostAttributeProfile(); + Set attributeSetOld = new Gson().fromJson(attributeOld, Set.class); + JsonArray telemetryOld = attrTelemetryObserveValueOld.getPostTelemetryProfile(); + Set telemetrySetOld = new Gson().fromJson(telemetryOld, Set.class); + JsonArray observeOld = attrTelemetryObserveValueOld.getPostObserveProfile(); + JsonObject keyNameOld = attrTelemetryObserveValueOld.getPostKeyNameProfile(); + + AttrTelemetryObserveValue attrTelemetryObserveValueNew = lwM2mInMemorySecurityStore.getProfiles().get(deviceProfile.getUuidId()); + JsonArray attributeNew = attrTelemetryObserveValueNew.getPostAttributeProfile(); + Set attributeSetNew = new Gson().fromJson(attributeNew, Set.class); + JsonArray telemetryNew = attrTelemetryObserveValueNew.getPostTelemetryProfile(); + Set telemetrySetNew = new Gson().fromJson(telemetryNew, Set.class); + JsonArray observeNew = attrTelemetryObserveValueNew.getPostObserveProfile(); + JsonObject keyNameNew = attrTelemetryObserveValueNew.getPostKeyNameProfile(); + // #2 + lwM2MClient.setDeviceProfileName(deviceProfile.getName()); + lwM2MClient.setProfileUuid(deviceProfile.getUuidId()); + + // #3 + ResultsAnalyzerParameters sentAttrToThingsboard = new ResultsAnalyzerParameters(); + // #3.1 + if (!attributeOld.equals(attributeNew)) { + ResultsAnalyzerParameters postAttributeAnalyzer = this.getAnalyzerParameters(new Gson().fromJson(attributeOld, Set.class), attributeSetNew); + sentAttrToThingsboard.getPathPostParametersAdd().addAll(postAttributeAnalyzer.getPathPostParametersAdd()); + sentAttrToThingsboard.getPathPostParametersDel().addAll(postAttributeAnalyzer.getPathPostParametersDel()); + } + // #3.2 + if (!attributeOld.equals(attributeNew)) { + ResultsAnalyzerParameters postTelemetryAnalyzer = this.getAnalyzerParameters(new Gson().fromJson(telemetryOld, Set.class), telemetrySetNew); + sentAttrToThingsboard.getPathPostParametersAdd().addAll(postTelemetryAnalyzer.getPathPostParametersAdd()); + sentAttrToThingsboard.getPathPostParametersDel().addAll(postTelemetryAnalyzer.getPathPostParametersDel()); + } + // #3.3 + if (!keyNameOld.equals(keyNameNew)) { + ResultsAnalyzerParameters keyNameChange = this.getAnalyzerKeyName(new Gson().fromJson(keyNameOld.toString(), ConcurrentHashMap.class), + new Gson().fromJson(keyNameNew.toString(), ConcurrentHashMap.class)); + sentAttrToThingsboard.getPathPostParametersAdd().addAll(keyNameChange.getPathPostParametersAdd()); + } + + // #4.1 add + if (sentAttrToThingsboard.getPathPostParametersAdd().size() > 0) { + // update value in Resources + this.updateResourceValueObserve(lwServer, registration, lwM2MClient, sentAttrToThingsboard.getPathPostParametersAdd(), GET_TYPE_OPER_READ); + // sent attr/telemetry to tingsboard for new path + this.updateAttrTelemetry(registration, false, sentAttrToThingsboard.getPathPostParametersAdd()); + } + // #4.2 del + if (sentAttrToThingsboard.getPathPostParametersDel().size() > 0) { + ResultsAnalyzerParameters sentAttrToThingsboardDel = this.getAnalyzerParameters(sentAttrToThingsboard.getPathPostParametersAdd(), sentAttrToThingsboard.getPathPostParametersDel()); + sentAttrToThingsboard.setPathPostParametersDel(sentAttrToThingsboardDel.getPathPostParametersDel()); + } + + // #5.1 + if (!observeOld.equals(observeNew)) { + Set observeSetOld = new Gson().fromJson(observeOld, Set.class); + Set observeSetNew = new Gson().fromJson(observeNew, Set.class); + //#5.2 add + // path Attr/Telemetry includes newObserve + attributeSetOld.addAll(telemetrySetOld); + ResultsAnalyzerParameters sentObserveToClientOld = this.getAnalyzerParametersIn(attributeSetOld, observeSetOld); // add observe + attributeSetNew.addAll(telemetrySetNew); + ResultsAnalyzerParameters sentObserveToClientNew = this.getAnalyzerParametersIn(attributeSetNew, observeSetNew); // add observe + // does not include oldObserve + ResultsAnalyzerParameters postObserveAnalyzer = this.getAnalyzerParameters(sentObserveToClientOld.getPathPostParametersAdd(), sentObserveToClientNew.getPathPostParametersAdd()); + // sent Request observe to Client + this.updateResourceValueObserve(lwServer, registration, lwM2MClient, postObserveAnalyzer.getPathPostParametersAdd(), GET_TYPE_OPER_OBSERVE); + // 5.3 del + // sent Request cancel observe to Client + this.cancelObserveIsValue(lwServer, registration, postObserveAnalyzer.getPathPostParametersDel()); + } + } + } + + /** + * Compare old list with new list after change AttrTelemetryObserve in config Profile + * + * @param parametersOld - + * @param parametersNew - + * @return ResultsAnalyzerParameters: add && new + */ + private ResultsAnalyzerParameters getAnalyzerParameters(Set parametersOld, Set parametersNew) { + ResultsAnalyzerParameters analyzerParameters = null; + if (!parametersOld.equals(parametersNew)) { + analyzerParameters = new ResultsAnalyzerParameters(); + analyzerParameters.setPathPostParametersAdd(parametersNew + .stream().filter(p -> !parametersOld.contains(p)).collect(Collectors.toSet())); + analyzerParameters.setPathPostParametersDel(parametersOld + .stream().filter(p -> !parametersNew.contains(p)).collect(Collectors.toSet())); + } + return analyzerParameters; + } + + private ResultsAnalyzerParameters getAnalyzerKeyName(ConcurrentMap keyNameOld, ConcurrentMap keyNameNew) { + ResultsAnalyzerParameters analyzerParameters = new ResultsAnalyzerParameters(); + Set paths = keyNameNew.entrySet() + .stream() + .filter(e -> !e.getValue().equals(keyNameOld.get(e.getKey()))) + .collect(Collectors.toMap(map -> map.getKey(), map -> map.getValue())).keySet(); + analyzerParameters.setPathPostParametersAdd(paths); + return analyzerParameters; + } + + private ResultsAnalyzerParameters getAnalyzerParametersIn(Set parametersObserve, Set parameters) { + ResultsAnalyzerParameters analyzerParameters = new ResultsAnalyzerParameters(); + analyzerParameters.setPathPostParametersAdd(parametersObserve + .stream().filter(p -> parameters.contains(p)).collect(Collectors.toSet())); + return analyzerParameters; + } + + /** + * Update Resource value after change RezAttrTelemetry in config Profile + * sent response Read to Client and add path to pathResAttrTelemetry in LwM2MClient.getAttrTelemetryObserveValue() + * + * @param lwServer - LeshanServer + * @param registration - Registration LwM2M Client + * @param lwM2MClient - object with All parameters off client + * @param targets - path Resources == [ "/2/0/0", "/2/0/1"] + */ + private void updateResourceValueObserve(LeshanServer lwServer, Registration registration, LwM2MClient lwM2MClient, Set targets, String typeOper) { + targets.stream().forEach(target -> { + ResultIds pathIds = new ResultIds(target); + if (pathIds.resourceId >= 0 && lwM2MClient.getModelObjects().get(pathIds.getObjectId()) + .getInstances().get(pathIds.getInstanceId()).getResource(pathIds.getResourceId()).getValue() != null) { + if (GET_TYPE_OPER_READ.equals(typeOper)) { + lwM2MTransportRequest.sendAllRequest(lwServer, registration, target, typeOper, + ContentFormat.TLV.getName(), null, null, null, this.context.getCtxServer().getTimeout()); + } else if (GET_TYPE_OPER_OBSERVE.equals(typeOper)) { + lwM2MTransportRequest.sendAllRequest(lwServer, registration, target, typeOper, + null, null, null, null, this.context.getCtxServer().getTimeout()); + } + } + }); + } + + private void cancelObserveIsValue(LeshanServer lwServer, Registration registration, Set paramAnallyzer) { + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getlwM2MClient(registration.getId()); + paramAnallyzer.forEach(p -> { + if (this.getResourceValue(lwM2MClient, p) != null) { + this.setCancelObservationRecourse(lwServer, registration, p); + } + } + ); + } + + private ResourceValue getResourceValue(LwM2MClient lwM2MClient, String path) { + ResourceValue resourceValue = null; + ResultIds pathIds = new ResultIds(path); + if (pathIds.getResourceId() > -1) { + LwM2mResource resource = lwM2MClient.getModelObjects().get(pathIds.getObjectId()).getInstances().get(pathIds.getInstanceId()).getResource(pathIds.getResourceId()); + if (resource.isMultiInstances()) { + Map values = resource.getValues(); + if (resource.getValues().size() > 0) { + resourceValue = new ResourceValue(); + resourceValue.setMultiInstances(resource.isMultiInstances()); + resourceValue.setValues(resource.getValues()); + } + } else { + if (resource.getValue() != null) { + resourceValue = new ResourceValue(); + resourceValue.setMultiInstances(resource.isMultiInstances()); + resourceValue.setValue(resource.getValue()); + } + } + } + return resourceValue; + } + + /** + * Trigger Server path = "/1/0/8" + * + * Trigger bootStrap path = "/1/0/9" - have to implemented on client + */ + public void doTrigger(LeshanServer lwServer, Registration registration, String path) { + lwM2MTransportRequest.sendAllRequest(lwServer, registration, path, POST_TYPE_OPER_EXECUTE, + ContentFormat.TLV.getName(), null, null, null, this.context.getCtxServer().getTimeout()); + } + + /** + * Session device in thingsboard is closed + * + * @param sessionInfo - lwm2m client + */ + private void doCloseSession(SessionInfoProto sessionInfo) { + TransportProtos.SessionEvent event = SessionEvent.CLOSED; + TransportProtos.SessionEventMsg msg = TransportProtos.SessionEventMsg.newBuilder() + .setSessionType(TransportProtos.SessionType.ASYNC) + .setEvent(event).build(); + transportService.process(sessionInfo, msg, null); + } + + /** + * Deregister session in transport + * @param sessionInfo - lwm2m client + */ + private void doDisconnect(SessionInfoProto sessionInfo) { + transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.CLOSED), null); + transportService.deregisterSession(sessionInfo); + } + + private void checkInactivityAndReportActivity() { + lwM2mInMemorySecurityStore.getSessions().forEach((key, value) -> transportService.reportActivity(this.getValidateSessionInfo(key))); + } + + public void sentLogsToThingsboard(String msg, String registrationId) { + if (msg != null) { + JsonObject telemetrys = new JsonObject(); + telemetrys.addProperty(LOG_LW2M_TELEMETRY, msg); + this.updateParametersOnThingsboard(telemetrys, LwM2MTransportHandler.DEVICE_TELEMETRY_TOPIC, registrationId); + } + } + +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java new file mode 100644 index 0000000000..4d63da3580 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java @@ -0,0 +1,111 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.server; + +import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.observation.Observation; +import org.eclipse.leshan.core.response.ObserveResponse; +import org.eclipse.leshan.server.californium.LeshanServer; +import org.eclipse.leshan.server.observation.ObservationListener; +import org.eclipse.leshan.server.queue.PresenceListener; +import org.eclipse.leshan.server.registration.Registration; +import org.eclipse.leshan.server.registration.RegistrationListener; +import org.eclipse.leshan.server.registration.RegistrationUpdate; + +import java.util.Collection; + +@Slf4j +public class LwM2mServerListener { + private LeshanServer lhServer; + private LwM2MTransportService service; + + public LwM2mServerListener(LeshanServer lhServer, LwM2MTransportService service) { + this.lhServer = lhServer; + this.service = service; + } + + public final RegistrationListener registrationListener = new RegistrationListener() { + /** + * Register – запрос, представленный в виде POST /rd?… + */ + @Override + public void registered(Registration registration, Registration previousReg, + Collection previousObsersations) { + + service.onRegistered(lhServer, registration, previousObsersations); + } + + /** + * Update – представляет из себя CoAP POST запрос на URL, полученный в ответ на Register. + */ + @Override + public void updated(RegistrationUpdate update, Registration updatedRegistration, + Registration previousRegistration) { + service.updatedReg(lhServer, updatedRegistration); + } + + /** + * De-register (CoAP DELETE) – отправляется клиентом в случае инициирования процедуры выключения. + */ + @Override + public void unregistered(Registration registration, Collection observations, boolean expired, + Registration newReg) { + service.unReg(registration, observations); + } + + }; + + public final PresenceListener presenceListener = new PresenceListener() { + @Override + public void onSleeping(Registration registration) { + service.onSleepingDev(registration); + } + + @Override + public void onAwake(Registration registration) { + service.onAwakeDev(registration); + } + }; + + public final ObservationListener observationListener = new ObservationListener() { + + @Override + public void cancelled(Observation observation) { + log.info("Received notification cancelled from [{}] ", observation.getPath()); + } + + @Override + public void onResponse(Observation observation, Registration registration, ObserveResponse response) { + if (registration != null) { + try { + service.onObservationResponse(registration, observation.getPath().toString(), response); + } catch (java.lang.NullPointerException e) { + log.error(e.toString()); + } + } + } + + @Override + public void onError(Observation observation, Registration registration, Exception error) { + log.error(String.format("Unable to handle notification of [%s:%s]", observation.getRegistrationId(), observation.getPath()), error); + } + + @Override + public void newObservation(Observation observation, Registration registration) { + log.info("Received newObservation from [{}] endpoint [{}] ", observation.getPath(), registration.getEndpoint()); + } + }; +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ResultIds.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ResultIds.java new file mode 100644 index 0000000000..b5c2f6638e --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ResultIds.java @@ -0,0 +1,38 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.server; + +import lombok.Builder; +import lombok.Data; + +@Data +public class ResultIds { + @Builder.Default + int objectId = -1; + @Builder.Default + int instanceId = -1; + @Builder.Default + int resourceId = -1; + + public ResultIds (String path) { + String[] paths = path.split("/"); + if (paths != null && paths.length > 1) { + this.objectId = (paths.length > 1) ? Integer.parseInt(paths[1]) : this.objectId; + this.instanceId = (paths.length > 2) ? Integer.parseInt(paths[2]) : this.instanceId; + this.resourceId = (paths.length > 3) ? Integer.parseInt(paths[3]) : this.resourceId; + } + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/adaptors/LwM2MJsonAdaptor.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/adaptors/LwM2MJsonAdaptor.java new file mode 100644 index 0000000000..47dbe563a2 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/adaptors/LwM2MJsonAdaptor.java @@ -0,0 +1,49 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.server.adaptors; + +import com.google.gson.JsonElement; +import com.google.gson.JsonSyntaxException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Component; +import org.thingsboard.server.common.transport.adaptor.AdaptorException; +import org.thingsboard.server.common.transport.adaptor.JsonConverter; +import org.thingsboard.server.gen.transport.TransportProtos; + +@Slf4j +@Component("LwM2MJsonAdaptor") +@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' )|| ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") +public class LwM2MJsonAdaptor implements LwM2MTransportAdaptor { + + @Override + public TransportProtos.PostTelemetryMsg convertToPostTelemetry(JsonElement jsonElement) throws AdaptorException { + try { + return JsonConverter.convertToTelemetryProto(jsonElement); + } catch (IllegalStateException | JsonSyntaxException ex) { + throw new AdaptorException(ex); + } + } + + @Override + public TransportProtos.PostAttributeMsg convertToPostAttributes(JsonElement jsonElement) throws AdaptorException { + try { + return JsonConverter.convertToAttributesProto(jsonElement); + } catch (IllegalStateException | JsonSyntaxException ex) { + throw new AdaptorException(ex); + } + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/adaptors/LwM2MTransportAdaptor.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/adaptors/LwM2MTransportAdaptor.java new file mode 100644 index 0000000000..d4d54f4df8 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/adaptors/LwM2MTransportAdaptor.java @@ -0,0 +1,27 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.server.adaptors; + +import com.google.gson.JsonElement; +import org.thingsboard.server.common.transport.adaptor.AdaptorException; +import org.thingsboard.server.gen.transport.TransportProtos; + +public interface LwM2MTransportAdaptor { + + TransportProtos.PostTelemetryMsg convertToPostTelemetry(JsonElement jsonElement) throws AdaptorException; + + TransportProtos.PostAttributeMsg convertToPostAttributes(JsonElement jsonElement) throws AdaptorException; +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/AttrTelemetryObserveValue.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/AttrTelemetryObserveValue.java new file mode 100644 index 0000000000..fb800c8197 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/AttrTelemetryObserveValue.java @@ -0,0 +1,47 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.server.client; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import lombok.Data; + +@Data +public class AttrTelemetryObserveValue { + /** + * {"keyName": { + * "/3/0/1": "modelNumber", + * "/3/0/0": "manufacturer", + * "/3/0/2": "serialNumber" + * } + **/ + JsonObject postKeyNameProfile; + + /** + * [ "/2/0/0", "/2/0/1"] + */ + JsonArray postAttributeProfile; + + /** + * [ "/2/0/0", "/2/0/1"] + */ + JsonArray postTelemetryProfile; + + /** + * [ "/2/0/0", "/2/0/1"] + */ + JsonArray postObserveProfile; +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java new file mode 100644 index 0000000000..3a84a637ac --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java @@ -0,0 +1,107 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.server.client; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.model.ObjectModel; +import org.eclipse.leshan.core.node.LwM2mObjectInstance; +import org.eclipse.leshan.core.response.LwM2mResponse; +import org.eclipse.leshan.core.response.ReadResponse; +import org.eclipse.leshan.server.californium.LeshanServer; +import org.eclipse.leshan.server.registration.Registration; +import org.eclipse.leshan.server.security.SecurityInfo; +import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; +import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportService; +import org.thingsboard.server.transport.lwm2m.server.ResultIds; + +import java.util.UUID; +import java.util.Map; +import java.util.Set; +import java.util.Collection; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +@Slf4j +@Data +public class LwM2MClient implements Cloneable { + private String deviceName; + private String deviceProfileName; + private String endPoint; + private String identity; + private SecurityInfo info; + private UUID deviceUuid; + private UUID sessionUuid; + private UUID profileUuid; + private LeshanServer lwServer; + private LwM2MTransportService lwM2MTransportService; + private Registration registration; + private ValidateDeviceCredentialsResponseMsg credentialsResponse; + private Map attributes; + private Map modelObjects; + private Set pendingRequests; + private Map responses; + + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } + + public LwM2MClient(String endPoint, String identity, SecurityInfo info, ValidateDeviceCredentialsResponseMsg credentialsResponse, Map attributes, Map modelObjects, UUID profileUuid) { + this.endPoint = endPoint; + this.identity = identity; + this.info = info; + this.credentialsResponse = credentialsResponse; + this.attributes = (attributes != null && attributes.size() > 0) ? attributes : new ConcurrentHashMap(); + this.modelObjects = (modelObjects != null && modelObjects.size() > 0) ? modelObjects : new ConcurrentHashMap(); + this.pendingRequests = ConcurrentHashMap.newKeySet(); + this.profileUuid = profileUuid; + /** + * Key , response instance -> resources: value...> + */ + this.responses = new ConcurrentHashMap<>(); + } + + /** + * Fill with data -> Model client + * @param path - + * @param response - + */ + public void onSuccessHandler(String path, LwM2mResponse response) { + this.responses.put(path, response); + this.pendingRequests.remove(path); + if (this.pendingRequests.size() == 0) { + this.initValue(); + this.lwM2MTransportService.updatesAndSentModelParameter(this.lwServer, this.registration); + } + } + + private void initValue() { + this.responses.forEach((key, resp) -> { + ResultIds pathIds = new ResultIds(key); + if (pathIds.getObjectId() > -1) { + ObjectModel objectModel = ((Collection) this.lwServer.getModelProvider().getObjectModel(registration).getObjectModels()).stream().filter(v -> v.id == pathIds.getObjectId()).collect(Collectors.toList()).get(0); + if (this.modelObjects.get(pathIds.getObjectId()) != null) { + this.modelObjects.get(pathIds.getObjectId()).getInstances().put(((ReadResponse) resp).getContent().getId(), (LwM2mObjectInstance) ((ReadResponse) resp).getContent()); + } else { + Map instances = new ConcurrentHashMap<>(); + instances.put(((ReadResponse) resp).getContent().getId(), (LwM2mObjectInstance) ((ReadResponse) resp).getContent()); + ModelObject modelObject = new ModelObject(objectModel, instances); + this.modelObjects.put(pathIds.getObjectId(), modelObject); + } + } + }); + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ModelObject.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ModelObject.java new file mode 100644 index 0000000000..03dcc5013f --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ModelObject.java @@ -0,0 +1,41 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.server.client; + +import lombok.Data; +import org.eclipse.leshan.core.model.ObjectModel; +import org.eclipse.leshan.core.node.LwM2mObjectInstance; +import java.util.Map; + +@Data +public class ModelObject { + /** + * model one on all instance + * for each instance only id resource with parameters of resources (observe, attr, telemetry) + */ + private ObjectModel objectModel; + private Map instances; + + public ModelObject(ObjectModel objectModel, Map instances) { + this.objectModel = objectModel; + this.instances = instances; + } + + public boolean removeInstance (int id ) { + LwM2mObjectInstance instance = this.instances.get(id); + return this.instances.remove(id, instance); + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResourceValue.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResourceValue.java new file mode 100644 index 0000000000..312973b9d0 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResourceValue.java @@ -0,0 +1,26 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.server.client; + +import lombok.Data; +import java.util.Map; + +@Data +public class ResourceValue { + Map values; + Object value; + boolean multiInstances; +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResultsAnalyzerParameters.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResultsAnalyzerParameters.java new file mode 100644 index 0000000000..dcb561b699 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResultsAnalyzerParameters.java @@ -0,0 +1,32 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.server.client; + +import lombok.Data; + +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +@Data +public class ResultsAnalyzerParameters { + Set pathPostParametersAdd; + Set pathPostParametersDel; + + public ResultsAnalyzerParameters() { + this.pathPostParametersAdd = ConcurrentHashMap.newKeySet(); + this.pathPostParametersDel = ConcurrentHashMap.newKeySet(); + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2MSetSecurityStoreServer.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2MSetSecurityStoreServer.java new file mode 100644 index 0000000000..7a37ac4005 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2MSetSecurityStoreServer.java @@ -0,0 +1,234 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.server.secure; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.util.Hex; +import org.eclipse.leshan.server.californium.LeshanServerBuilder; +import org.eclipse.leshan.server.redis.RedisRegistrationStore; +import org.eclipse.leshan.server.redis.RedisSecurityStore; +import org.eclipse.leshan.server.security.DefaultAuthorizer; +import org.eclipse.leshan.server.security.EditableSecurityStore; +import org.eclipse.leshan.server.security.SecurityChecker; +import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode; +import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportContextServer; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPool; +import redis.clients.jedis.util.Pool; + +import java.math.BigInteger; +import java.net.URI; +import java.net.URISyntaxException; +import java.security.KeyStore; +import java.security.PublicKey; +import java.security.PrivateKey; +import java.security.AlgorithmParameters; +import java.security.KeyFactory; +import java.security.GeneralSecurityException; +import java.security.KeyStoreException; +import java.security.cert.X509Certificate; +import java.security.interfaces.ECPublicKey; +import java.security.spec.*; +import java.util.Arrays; + +import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.*; + +@Slf4j +@Data +public class LwM2MSetSecurityStoreServer { + + private KeyStore keyStore; + private X509Certificate certificate; + private PublicKey publicKey; + private PrivateKey privateKey; + private LwM2MTransportContextServer context; + private LwM2mInMemorySecurityStore lwM2mInMemorySecurityStore; + + private LeshanServerBuilder builder; + EditableSecurityStore securityStore; + + public LwM2MSetSecurityStoreServer(LeshanServerBuilder builder, LwM2MTransportContextServer context, LwM2mInMemorySecurityStore lwM2mInMemorySecurityStore, LwM2MSecurityMode dtlsMode) { + this.builder = builder; + this.context = context; + this.lwM2mInMemorySecurityStore = lwM2mInMemorySecurityStore; + /** Set securityStore with new registrationStore */ + switch (dtlsMode) { + /** Use PSK only */ + case PSK: + generatePSK_RPK(); + if (this.privateKey != null && this.privateKey.getEncoded().length > 0) { + builder.setPrivateKey(this.privateKey); + builder.setPublicKey(null); + getParamsPSK(); + } + break; + /** Use RPK only */ + case RPK: + generatePSK_RPK(); + if (this.publicKey != null && this.publicKey.getEncoded().length > 0 && + this.privateKey != null && this.privateKey.getEncoded().length > 0) { + builder.setPublicKey(this.publicKey); + builder.setPrivateKey(this.privateKey); + getParamsRPK(); + } + break; + /** Use x509 only */ + case X509: + setServerWithX509Cert(); + break; + /** No security */ + case NO_SEC: + builder.setTrustedCertificates(new X509Certificate[0]); + break; + /** Use x509 with EST */ + case X509_EST: + // TODO support sentinel pool and make pool configurable + break; + case REDIS: + /** + * Set securityStore with new registrationStore (if use redis store) + * Connect to redis + */ + Pool jedis = null; + try { + jedis = new JedisPool(new URI(this.context.getCtxServer().getRedisUrl())); + securityStore = new RedisSecurityStore(jedis); + builder.setRegistrationStore(new RedisRegistrationStore(jedis)); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + break; + default: + } + + /** Set securityStore with new registrationStore (if not redis)*/ + if (dtlsMode.code < REDIS.code) { + securityStore = lwM2mInMemorySecurityStore; + if (dtlsMode == X509) { + builder.setAuthorizer(new DefaultAuthorizer(securityStore, new SecurityChecker() { + @Override + protected boolean matchX509Identity(String endpoint, String receivedX509CommonName, + String expectedX509CommonName) { + return endpoint.startsWith(expectedX509CommonName); + } + })); + } + } + + /** Set securityStore with new registrationStore */ + builder.setSecurityStore(securityStore); + } + + private void generatePSK_RPK() { + try { + /** Get Elliptic Curve Parameter spec for secp256r1 */ + AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC"); + algoParameters.init(new ECGenParameterSpec("secp256r1")); + ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class); + if (this.context.getCtxServer().getServerPublicX() != null && !this.context.getCtxServer().getServerPublicX().isEmpty() && this.context.getCtxServer().getServerPublicY() != null && !this.context.getCtxServer().getServerPublicY().isEmpty()) { + /** Get point values */ + byte[] publicX = Hex.decodeHex(this.context.getCtxServer().getServerPublicX().toCharArray()); + byte[] publicY = Hex.decodeHex(this.context.getCtxServer().getServerPublicY().toCharArray()); + /** Create key specs */ + KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)), + parameterSpec); + /** Get keys */ + this.publicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec); + } + if (this.context.getCtxServer().getServerPrivateS() != null && !this.context.getCtxServer().getServerPrivateS().isEmpty()) { + /** Get point values */ + byte[] privateS = Hex.decodeHex(this.context.getCtxServer().getServerPrivateS().toCharArray()); + /** Create key specs */ + KeySpec privateKeySpec = new ECPrivateKeySpec(new BigInteger(privateS), parameterSpec); + /** Get keys */ + this.privateKey = KeyFactory.getInstance("EC").generatePrivate(privateKeySpec); + } + } catch (GeneralSecurityException | IllegalArgumentException e) { + log.error("[{}] Failed generate Server PSK/RPK", e.getMessage()); + throw new RuntimeException(e); + } + } + + private void setServerWithX509Cert() { + try { + if (this.context.getCtxServer().getKeyStoreValue() != null) { + setBuilderX509(); + X509Certificate rootCAX509Cert = (X509Certificate) this.context.getCtxServer().getKeyStoreValue().getCertificate(this.context.getCtxServer().getRootAlias()); + if (rootCAX509Cert != null) { + X509Certificate[] trustedCertificates = new X509Certificate[1]; + trustedCertificates[0] = rootCAX509Cert; + builder.setTrustedCertificates(trustedCertificates); + } else { + /** by default trust all */ + builder.setTrustedCertificates(new X509Certificate[0]); + } + } + else { + /** by default trust all */ + this.builder.setTrustedCertificates(new X509Certificate[0]); + log.error("Unable to load X509 files for LWM2MServer"); + } + } catch (KeyStoreException ex) { + log.error("[{}] Unable to load X509 files server", ex.getMessage()); + } + } + + private void setBuilderX509() { + /** + * For deb => KeyStorePathFile == yml or commandline: KEY_STORE_PATH_FILE + * For idea => KeyStorePathResource == common/transport/lwm2m/src/main/resources/credentials: in LwM2MTransportContextServer: credentials/serverKeyStore.jks + */ + try { + X509Certificate serverCertificate = (X509Certificate) this.context.getCtxServer().getKeyStoreValue().getCertificate(this.context.getCtxServer().getServerAlias()); + PrivateKey privateKey = (PrivateKey) this.context.getCtxServer().getKeyStoreValue().getKey(this.context.getCtxServer().getServerAlias(), this.context.getCtxServer().getKeyStorePasswordServer() == null ? null : this.context.getCtxServer().getKeyStorePasswordServer().toCharArray()); + this.builder.setPrivateKey(privateKey); + this.builder.setCertificateChain(new X509Certificate[]{serverCertificate}); + } catch (Exception ex) { + log.error("[{}] Unable to load KeyStore files server", ex.getMessage()); + } + } + + private void getParamsPSK() { + log.info("\nServer uses PSK -> private key : \n security key : [{}] \n serverSecureURI : [{}]", + Hex.encodeHexString(this.privateKey.getEncoded()), + this.context.getCtxServer().getServerSecureHost() + ":" + Integer.toString(this.context.getCtxServer().getServerSecurePort())); + } + + private void getParamsRPK() { + if (this.publicKey instanceof ECPublicKey) { + /** Get x coordinate */ + byte[] x = ((ECPublicKey) this.publicKey).getW().getAffineX().toByteArray(); + if (x[0] == 0) + x = Arrays.copyOfRange(x, 1, x.length); + + /** Get Y coordinate */ + byte[] y = ((ECPublicKey) this.publicKey).getW().getAffineY().toByteArray(); + if (y[0] == 0) + y = Arrays.copyOfRange(y, 1, y.length); + + /** Get Curves params */ + String params = ((ECPublicKey) this.publicKey).getParams().toString(); + log.info( + " \nServer uses RPK : \n Elliptic Curve parameters : [{}] \n Public x coord : [{}] \n Public y coord : [{}] \n Public Key (Hex): [{}] \n Private Key (Hex): [{}]", + params, Hex.encodeHexString(x), Hex.encodeHexString(y), + Hex.encodeHexString(this.publicKey.getEncoded()), + Hex.encodeHexString(this.privateKey.getEncoded())); + } else { + throw new IllegalStateException("Unsupported Public Key Format (only ECPublicKey supported)."); + } + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java new file mode 100644 index 0000000000..394e7ee5f1 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java @@ -0,0 +1,212 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.server.secure; + +import com.google.gson.JsonObject; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.server.californium.LeshanServer; +import org.eclipse.leshan.server.registration.Registration; +import org.eclipse.leshan.server.security.InMemorySecurityStore; +import org.eclipse.leshan.server.security.SecurityInfo; +import org.eclipse.leshan.server.security.SecurityStoreListener; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.DeviceProfile; +import org.thingsboard.server.transport.lwm2m.secure.LwM2MGetSecurityInfo; +import org.thingsboard.server.transport.lwm2m.secure.ReadResultSecurityStore; +import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler; +import org.thingsboard.server.transport.lwm2m.server.client.AttrTelemetryObserveValue; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.utils.TypeServer; + +import java.util.Map; +import java.util.UUID; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.stream.Collectors; + +import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.*; + +@Slf4j +@Component("LwM2mInMemorySecurityStore") +@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' )|| ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") +public class LwM2mInMemorySecurityStore extends InMemorySecurityStore { + // lock for the two maps + protected final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); + protected final Lock readLock = readWriteLock.readLock(); + protected final Lock writeLock = readWriteLock.writeLock(); + private final boolean infosAreCompromised = false; + protected Map sessions = new ConcurrentHashMap<>(); + protected Map profiles = new ConcurrentHashMap<>(); + private SecurityStoreListener listener; + + @Autowired + LwM2MGetSecurityInfo lwM2MGetSecurityInfo; + + @Override + public SecurityInfo getByEndpoint(String endPoint) { + readLock.lock(); + try { + String registrationId = this.getByRegistrationId(endPoint, null); + return (registrationId != null && sessions.size() > 0 && sessions.get(registrationId) != null) ? sessions.get(registrationId).getInfo() : this.add(endPoint); + } finally { + readLock.unlock(); + } + } + + @Override + public SecurityInfo getByIdentity(String identity) { + readLock.lock(); + try { + String integrationId = this.getByRegistrationId(null, identity); + return (integrationId != null) ? sessions.get(integrationId).getInfo() : add(identity); + } finally { + readLock.unlock(); + } + } + + @Override + public Collection getAll() { + readLock.lock(); + try { + return Collections.unmodifiableCollection(this.sessions.entrySet().stream().map(model -> model.getValue().getInfo()).collect(Collectors.toList())); + } finally { + readLock.unlock(); + } + } + + /** + * Removed registration Client from sessions and listener + * @param registrationId if Client + */ + public void delRemoveSessionAndListener(String registrationId) { + writeLock.lock(); + try { + LwM2MClient lwM2MClient = (sessions.get(registrationId) != null) ? sessions.get(registrationId) : null; + if (lwM2MClient != null) { + if (listener != null) { + listener.securityInfoRemoved(infosAreCompromised, lwM2MClient.getInfo()); + } + sessions.remove(registrationId); + } + } finally { + writeLock.unlock(); + } + } + + @Override + public void setListener(SecurityStoreListener listener) { + this.listener = listener; + } + + public LwM2MClient getlwM2MClient(String endPoint, String identity) { + Map.Entry modelClients = (endPoint != null) ? + this.sessions.entrySet().stream().filter(model -> endPoint.equals(model.getValue().getEndPoint())).findAny().orElse(null) : + this.sessions.entrySet().stream().filter(model -> identity.equals(model.getValue().getIdentity())).findAny().orElse(null); + return (modelClients != null) ? modelClients.getValue() : null; + } + + public LwM2MClient getlwM2MClient(String registrationId) { + return this.sessions.get(registrationId); + } + + public LwM2MClient getlwM2MClient(LeshanServer lwServer, Registration registration) { + writeLock.lock(); + try { + if (this.sessions.get(registration.getEndpoint()) == null) { + this.add(registration.getEndpoint()); + } + LwM2MClient lwM2MClient = this.sessions.get(registration.getEndpoint()); + lwM2MClient.setLwServer(lwServer); + lwM2MClient.setRegistration(registration); + lwM2MClient.setAttributes(registration.getAdditionalRegistrationAttributes()); + this.sessions.put(registration.getId(), lwM2MClient); + this.sessions.remove(registration.getEndpoint()); + return lwM2MClient; + } finally { + writeLock.unlock(); + } + } + + private String getByRegistrationId(String endPoint, String identity) { + List registrationIds = (endPoint != null) ? + this.sessions.entrySet().stream().filter(model -> endPoint.equals(model.getValue().getEndPoint())).map(model -> model.getKey()).collect(Collectors.toList()) : + this.sessions.entrySet().stream().filter(model -> identity.equals(model.getValue().getIdentity())).map(model -> model.getKey()).collect(Collectors.toList()); + return (registrationIds != null && registrationIds.size() > 0) ? registrationIds.get(0) : null; + } + + public String getByRegistrationId(String credentialsId) { + List registrationIds = (this.sessions.entrySet().stream().filter(model -> credentialsId.equals(model.getValue().getEndPoint())).map(model -> model.getKey()).collect(Collectors.toList()).size() > 0) ? + this.sessions.entrySet().stream().filter(model -> credentialsId.equals(model.getValue().getEndPoint())).map(model -> model.getKey()).collect(Collectors.toList()) : + this.sessions.entrySet().stream().filter(model -> credentialsId.equals(model.getValue().getIdentity())).map(model -> model.getKey()).collect(Collectors.toList()); + return (registrationIds != null && registrationIds.size() > 0) ? registrationIds.get(0) : null; + } + + public Registration getByRegistration(String registrationId) { + return this.sessions.get(registrationId).getRegistration(); + } + + private SecurityInfo add(String identity) { + ReadResultSecurityStore store = lwM2MGetSecurityInfo.getSecurityInfo(identity, TypeServer.CLIENT); + UUID profileUuid = (addUpdateProfileParameters(store.getDeviceProfile())) ? store.getDeviceProfile().getUuidId() : null; + if (store.getSecurityInfo() != null) { + if (store.getSecurityMode() < DEFAULT_MODE.code) { + String endpoint = store.getSecurityInfo().getEndpoint(); + sessions.put(endpoint, new LwM2MClient(endpoint, store.getSecurityInfo().getIdentity(), store.getSecurityInfo(), store.getMsg(), null, null, profileUuid)); + } + } else { + if (store.getSecurityMode() == NO_SEC.code) + sessions.put(identity, new LwM2MClient(identity, null, null, store.getMsg(), null, null, profileUuid)); + else log.error("Registration failed: FORBIDDEN, endpointId: [{}]", identity); + } + return store.getSecurityInfo(); + } + + public Map getSession (UUID sessionUuId){ + return this.sessions.entrySet().stream().filter(e -> e.getValue().getSessionUuid().equals(sessionUuId)).collect(Collectors.toMap(map -> map.getKey(), map -> map.getValue())); + } + + public Map getSessions() { + return this.sessions; + } + + public Map getProfiles() { + return this.profiles; + } + + public MapsetProfiles(Map profiles) { + return this.profiles = profiles; + } + + /** + * + * @param deviceProfile + */ + public boolean addUpdateProfileParameters(DeviceProfile deviceProfile) { + JsonObject profilesConfigData = LwM2MTransportHandler.getObserveAttrTelemetryFromThingsboard(deviceProfile); + if (profilesConfigData != null) { + profiles.put(deviceProfile.getUuidId(), LwM2MTransportHandler.getNewProfileParameters(profilesConfigData)); + } + return (profilesConfigData != null); + } + +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java new file mode 100644 index 0000000000..d7cae734a2 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java @@ -0,0 +1,146 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.utils; + +import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.model.ResourceModel.Type; +import org.eclipse.leshan.core.node.LwM2mPath; +import org.eclipse.leshan.core.node.codec.CodecException; +import org.eclipse.leshan.core.node.codec.LwM2mValueConverter; +import org.eclipse.leshan.core.util.Hex; +import org.eclipse.leshan.core.util.StringUtils; + +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeFactory; +import javax.xml.datatype.XMLGregorianCalendar; +import java.util.Date; + +@Slf4j +public class LwM2mValueConverterImpl implements LwM2mValueConverter { + + @Override + public Object convertValue(Object value, Type currentType, Type expectedType, LwM2mPath resourcePath) + throws CodecException { + if (expectedType == null) { + /** unknown resource, trusted value */ + return value; + } + + if (currentType == expectedType) { + /** expected type */ + return value; + } + + switch (expectedType) { + case INTEGER: + switch (currentType) { + case FLOAT: + log.debug("Trying to convert float value [{}] to integer", value); + Long longValue = ((Double) value).longValue(); + if ((double) value == longValue.doubleValue()) { + return longValue; + } + default: + break; + } + break; + case FLOAT: + switch (currentType) { + case INTEGER: + log.debug("Trying to convert integer value [{}] to float", value); + Double floatValue = ((Long) value).doubleValue(); + if ((long) value == floatValue.longValue()) { + return floatValue; + } + default: + break; + } + break; + case BOOLEAN: + switch (currentType) { + case STRING: + log.debug("Trying to convert string value {} to boolean", value); + if (StringUtils.equalsIgnoreCase((String) value, "true")) { + return true; + } else if (StringUtils.equalsIgnoreCase((String) value, "false")) { + return false; + } + break; + case INTEGER: + log.debug("Trying to convert int value {} to boolean", value); + Long val = (Long) value; + if (val == 1) { + return true; + } else if (val == 0) { + return false; + } + break; + default: + break; + } + break; + case TIME: + switch (currentType) { + case INTEGER: + log.debug("Trying to convert long value {} to date", value); + /** let's assume we received the millisecond since 1970/1/1 */ + return new Date((Long) value); + case STRING: + log.debug("Trying to convert string value {} to date", value); + /** let's assume we received an ISO 8601 format date */ + try { + DatatypeFactory datatypeFactory = DatatypeFactory.newInstance(); + XMLGregorianCalendar cal = datatypeFactory.newXMLGregorianCalendar((String) value); + return cal.toGregorianCalendar().getTime(); + } catch (DatatypeConfigurationException | IllegalArgumentException e) { + log.debug("Unable to convert string to date", e); + throw new CodecException("Unable to convert string (%s) to date for resource %s", value, + resourcePath); + } + default: + break; + } + break; + case STRING: + switch (currentType) { + case BOOLEAN: + case INTEGER: + case FLOAT: + return String.valueOf(value); + default: + break; + } + break; + case OPAQUE: + if (currentType == Type.STRING) { + /** let's assume we received an hexadecimal string */ + log.debug("Trying to convert hexadecimal string [{}] to byte array", value); + // TODO check if we shouldn't instead assume that the string contains Base64 encoded data + try { + return Hex.decodeHex(((String) value).toCharArray()); + } catch (IllegalArgumentException e) { + throw new CodecException("Unable to convert hexastring [%s] to byte array for resource %s", value, + resourcePath); + } + } + break; + default: + } + + throw new CodecException("Invalid value type for resource %s, expected %s, got %s", resourcePath, expectedType, + currentType); + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/TypeServer.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/TypeServer.java new file mode 100644 index 0000000000..8e1dde9693 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/TypeServer.java @@ -0,0 +1,29 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.utils; + +public enum TypeServer { + BOOTSTRAP(0, "bootstrap"), + CLIENT(1, "client"); + + public int code; + public String type; + + TypeServer(int code, String type) { + this.code = code; + this.type = type; + } +} diff --git a/common/transport/lwm2m/src/main/resources/credentials/serverKeyStore.jks b/common/transport/lwm2m/src/main/resources/credentials/serverKeyStore.jks new file mode 100644 index 0000000000000000000000000000000000000000..b5b6c9fa3c43118262f4c89b1ba319ef09b694d0 GIT binary patch literal 5716 zcma)qB?KfE>5`UM79>`>LrS_k1Z1TVP&x!r8kUe1VM&qhE)@w8Sh~AA zmi&2t^Sw25XYQRdbI#23ob%56ndklIKtidsv9WLo?xeTkAdo7uheNQdNgC*M#YWZ9C z8mtluT+B}uLJVIvNe`D=hTCtGC0g)8E|o0i_@b z<2`@}0RCrr0c-)*5SD+MU_nY;a=qs-?3o20i;F--p%6iF5g|cH$l(8gG9>n)%|!@z z`e~6E5#G>|r)1s2=wB!}k(R?oh60L<&#i@}v%BCdnBkr_vz`O3NxUnc)1(^JLQO`X zwV^mGbW}o64_&>?7Jy1|w}NaNo$EGd>HhAmm#N6Iv;_$&{cE?Bf|QKp0Gq#1JpbT$ z0IUHo|Mkj$0umJ!{@=3kibVTk`D@QL$9rwJ;V+EnGxGud0;;rg1_zNtQ=BRb2G*rk z1{WwmgJh<>=_BRh#8DPGxo=GRkn6h)S%ZV2IHFd4%w5-#$#p#yLTagW95m4%RqftYWhsK@*a6EN-rNBoq z+xux$aP8hQmpM^CsXSG5A!Q=@BOmD);TF?)bozM*K#acDrgh?^zPgoP6n-D@$nxW2P%Sa-k*uH}WFVH19iZtl0c zruOT#PpS#YiRmfbE6EO2WO!-9-Dn|>dN8?}^jKRKNU8zp05L%~o-&8Ib*McQ3BluF zNS`Xmx9fXAjca|+KA>!p;SK!rhu~b(a5}qnDj3**$$L%k<9X6nb_0xl%!F%5F*)% z<_%aH^l>CZbg$8fSNaY@62pK+K^dZ4)Wh}K@vU9T_-9Y)t3vFO`g#DU@-o7C7SFUn zcBV?R*Uj#}X0UWH7<0ZFCP8d6bA$IG%C=>5b_=m_^wX7267A#Nxci(>(hDVyJO0I* z7apu;$`x^!M`<-A+TnlVJ17L!9%Mu{sdB0SO)*^I&NMN6?z!U(Vza56>@uS-cP?9K z&0X!}gx7W?yAP^I(oI-Ew0CHJBQDSx962H{i&O1);>NWue0sx5Ds|ZG&l

t^Q*A zz2VM8H6^(VvE-u{#!Femel3CiPESCye(B!J&u9D^V`M zz$xC-NvsP}_BiwB(fc_NofT2Z4!P=CK_}{F-tF`>5R< z0@q0@4pHjD`*pRfU*h%?$!tnIh3B0J3qmQ`Dn&BL53X^0d@608MOLsDcM9d=aMI3? z&LfTUeC`$p(Zdv{5-u=YoU84x?)H6KWZVZG3UNV7B4pvsX9;3!>cU+`ik<~@5&gxw zP)H5EPJ?M zV5ndrZ&-|4@MGH=z1LgMU^-DgyUb>^MJFdH(OUDQ;Rp76!uOwMgPd`2Ij|SL4D{QX zNv<4r``x)@#4$Y4HSV_%$UCraFe1cRX!-T7+PbO%mD?ul9zd&eL)y3MYlZqolkSvA zVs(+}tI&#rm|v+Ky59JOxIL-U889}w@iZCp{W$@PSbZPV)y7DRV5qPab37rH>0fVR z>73o~$Vq)WFTQIU4Gz>IAiDW5j{h{BS7h3dSb+`nwu~%!os=)#jz;|9RY6v&Ov-!% zowQ)>2kbaR_&srS4&yINtZ7?%8jLw%K2vkmrcM5ChRpS{9LPhUUYsi+&sklq44Ztx zfU@kpDA$ElBu5H+Q8Bq`c(HDGSuMymJC3Bs2 z;OcTnnpOl*EoEQn!_S_Z!+@W|4sR}HDiH&(a3wP<&^~#yf+Y%&Ph0uH`j=bb!;!`B zu|UE#6H4#46F9fn3w)0g5FD>_WY%7bzI;n|_KUqEbxSYt&B13!QVL4!Rz+4c#kKln zrw&FqI6^#IN?kGf69&zHfkR+bO40DUpwDnw?F?Jl0=is00b+!^Q5zt+V42>mQ!cC? zMxhilcUgUlD;O-&h`883!Vr}J!IB;Wmd9y~d{(aqe* zCHp7^wEqkx3Qi`gwKsJsZQw`jPUwc?D*$C@DzSX-GlN7vkq+2mH+f23!2hrxn874? zv_2%k`|Fy!@ze*oZsun0oOpvMwCsGSPYI@1H=~z++p`+&)+Z=u49Z&V{?G}P*^yvh zfzihAOgY`kd0n{FFe{_CNOtH4NRG#|`K9=Sck{QyFSC@#!)n59hEm=y1#no-DAiR* zNcdH7nz}aNQzaA@IIh<{*A2*TbsryTC^TgoE)yJ7W$UUxDD{5CTOGQ~& zDLV(hxqS4(2nwSVMyef{4P>HUrWXu}fJlV>f;6mnVvz0?Je!G1_3(kNS z!!F9Nw#7@bc%&o0)qW5iywwP97rM@Cdgwu&JQ5ZttGVomP9TTv{&eF|9zv+=750Q+ zaQMcI3Cj$uyTUTJRw=yo@D8pDCpvo_N7vU0BJv1tibIEL!Xya7xT4y$YkaRh?eE@V zD=P2L%TwvqV*w11I%r~xfxvBo(n>8(#-xsIN!zX7{v0YJ3*{q&b-@Ajmt28&E4SB5 zC<|Dw2(6)}Smlj~u6$fy>;)@+WHD42K*s|SdQhda8Kica=@=^cZP37MLk$b_7_lKy zul6_}h(;l#UB!+FHhmV<#`exzS3^4N7_4t%l~?KM^*_8Uu1b1f3A18kblJt~bX0bn zl*|jd?m&Qe9+LXAc`kN#i3%{hRPThRWA0PDF}b~sAj535@g=6}_Gyk|z*B`PcXbRl zUm2A-fd=APyhAabdJV{q!O5E5#&H2q?aFvAKG#xAz5&PESE;lR3KNeoqG?P!)I7sC z{MeVDg#5CpGd*`;XIF!=zIaw)7$2XHOwP2aDyQ^gZuR@{7Npr=KV6;QDW?FjLnY_T zo5A6G8}kQ)Yb4j(rRB&n9_~|g_Dr+H>aeguZYU;(S6b=6JV_>)(6I0v1IHw zEf!ZOhm(~dI4o5w)JchDhGNo7IsXPPeg3LiCki1-Qhl)qMRQ#fcfO+38)tOk%8@lVP z#e=F)w3hNyvLaQj-I2dYX^$F{H{el=f~(SDy>c`akd)F`EiDX;slE`&ga_6wZ`O}; z`3P=I4C6~s@d7!-rH)kYUug$*%z-%>Hti*ijmBOY+Ss_3n2$gnv3p59$$+!rF9{7L z!0vQV71n|=5n=-<*NkkRx?jw!%|}KBkSU;Wt!2KJguTF=^|^=-T>zY$0Gx$Rjbp8U7(5g`R| z2lO0p>(ii*Mp5(y19wH!V0W1Fa&wi7Pola3$D<8O%Z{Mkc zsG#b2MeQ~i~8Cw1o4-og?YmTn?G$GzK*XrFzBRxh+d4=Xh}^Dk%GX%2M{jaD*g z9$Ul2u-m{L|LIo`K04$(oW3-cg9+)&XhamLHJr$E6yM~{z80M%rvz_ZZpBpl_>@=i zpo#4P9E;b9>D$%gy&B-xIKgYbi|apvWo8R(+wod=7gI9xc=> zOV4lE$|1n=%h|1c`dR7R5*nH-lDv! z%wu*K-U(bw4;U9q839}S4{lD(H!Ty);YQ#cC}L317bwMVQYktcD_q28q>y=u@5FCw zwfdC@Pkh%X%D;$^MlQKyOkq7qJzu9a;p6denhpE9ypwP^9~XFj_I}go5VwwP<&VAi z6VvqhC()mCel0ice({ob{W&Mx(z(v6Yuj(qYr=Jf>^b4(*|!`XGuXt5ta+=CTo=ko zN20d89d%B-n3OWC;YZ)Wv@zO`O)c)YjXTXSn>$U%T*{2CRj}tj!Z%ONCnANoryL{K zu!wwf+S<-{e*x?Yn$n8IORBZmGN@nNSR5kdJXxGYnj?z&SU+!zSF5e@Z?GE=3u5qh z(yQip6>xYtm`XFqQRbg=V=QY56+B}`E#u~yW6N#oXHpz##5TijonNIxW(#3j+EI)q z)M;$KGmXG*y8Bz@jyg`&@JiaIrh=$VLHZHdL@&CRxOyal4poNX`8h<1ILw&U#Y+~M zjbvrrHT{a$4)qJ4fvgx(Ieo`=0Yw{eCu_WMs}#U|SN6cq`jvzv-I2y|%vO_y?YeRS zXU!_oKf7)s4mRZ=D#0BS^xZ7yt%Oy;{WTY*y&)N`wvj&iSttKsx!>h@Z$4y3gb@|a z>BgTazbH_w%PGmF@tC_>4#v)cer&%K%VWWKNgX^5D;T8DXXfF_7Z<2TvGGsm~NuR zvqMUBqBr<=apnX6CWlEIoBl`{-G+xw;U+hrXUyG9`=POP$CIL^6v<}cI2q*9;`H|i zo!!sQ`zKz$_vheHlBMd*wCa}QdlB~_a~+Y`$aJa4S2F_Ph>ZgX0bjiX?uT zX&d7LyBF``a8Oe}?tf|bWg->|Bgj?lccoI@sTagXQy*CcSe5VYNo&xUe+#4RHl(uE zulHEdz}NfkcU&_3tj$;K0hgWj4PBLY-xq~OKhez2|4$C{SY1uUklvotUGZ?CGbDHDF;?N$gDt)i}$)dV=yaYEGI;coQc5P`K z`UPq^SJwI3ez~1(1y%Pbd#2>pD(fTBeCN;3fLQ)(N}K7vQvQ@z##LXlo+djeI!EiOu#@X2 z?(n#SKT8Rr3#}iSK&6^=o5Ecjl5bqHQ4mK?w0GBdcw7a$V8kDQ| qkcRm%4dLuH%rb{d=@zQVZ?hk0O%Ryaxn;x~P%wJagN=g~iTppw$f0Ne literal 0 HcmV?d00001 diff --git a/common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh b/common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh new file mode 100755 index 0000000000..fd07df3feb --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh @@ -0,0 +1,208 @@ +#!/bin/sh +# +# Copyright © 2016-2020 The Thingsboard Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# source the properties: +. ./lwM2M_keygen.properties + +# Generation of the keystore. +echo "${H0}====START========${RESET}" +echo "${H1}Server Keystore : ${RESET}" +echo "${H1}==================${RESET}" +echo "${H2}Creating the trusted root CA key and certificate...${RESET}" +# -keysize +# 1024 (when using -genkeypair) +keytool \ + -genkeypair \ + -alias $ROOT_KEY_ALIAS \ + -keyalg EC \ + -dname "CN=$ROOT_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ + -validity $VALIDITY \ + -storetype $STORETYPE \ + -keypass $SERVER_STORE_PWD \ + -keystore $SERVER_STORE \ + -storepass $SERVER_STORE_PWD + +echo +echo "${H2}Creating server key and self-signed certificate ...${RESET}" +keytool \ + -genkeypair \ + -alias $SERVER_ALIAS \ + -keyalg EC \ + -dname "CN=$SERVER_SELF_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ + -validity $VALIDITY \ + -storetype $STORETYPE \ + -keypass $SERVER_STORE_PWD \ + -keystore $SERVER_STORE \ + -storepass $SERVER_STORE_PWD +keytool \ + -exportcert \ + -alias $SERVER_ALIAS \ + -keystore $SERVER_STORE \ + -storepass $SERVER_STORE_PWD | \ + keytool \ + -importcert \ + -alias $SERVER_SELF_ALIAS \ + -keystore $SERVER_STORE \ + -storepass $SERVER_STORE_PWD \ + -noprompt + +echo +echo "${H2}Creating server certificate signed by root CA...${RESET}" +keytool \ + -certreq \ + -alias $SERVER_ALIAS \ + -dname "CN=$SERVER_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ + -keystore $SERVER_STORE \ + -storepass $SERVER_STORE_PWD | \ + keytool \ + -gencert \ + -alias $ROOT_KEY_ALIAS \ + -keystore $SERVER_STORE \ + -storepass $SERVER_STORE_PWD \ + -storetype $STORETYPE \ + -validity $VALIDITY | \ + keytool \ + -importcert \ + -alias $SERVER_ALIAS \ + -keystore $SERVER_STORE \ + -storepass $SERVER_STORE_PWD + +echo +echo "${H2}Creating server key and self-signed certificate ...${RESET}" +keytool \ + -genkeypair \ + -alias $BOOTSTRAP_ALIAS \ + -keyalg EC \ + -dname "CN=$BOOTSTRAP_SELF_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ + -validity $VALIDITY \ + -storetype $STORETYPE \ + -keypass $SERVER_STORE_PWD \ + -keystore $SERVER_STORE \ + -storepass $SERVER_STORE_PWD +keytool \ + -exportcert \ + -alias $BOOTSTRAP_ALIAS \ + -keystore $SERVER_STORE \ + -storepass $SERVER_STORE_PWD | \ + keytool \ + -importcert \ + -alias $BOOTSTRAP_SELF_ALIAS \ + -keystore $SERVER_STORE \ + -storepass $SERVER_STORE_PWD \ + -noprompt + +echo +echo "${H2}Creating bootstrap certificate signed by root CA...${RESET}" +keytool \ + -certreq \ + -alias $BOOTSTRAP_ALIAS \ + -dname "CN=$BOOTSTRAP_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ + -keystore $SERVER_STORE \ + -storepass $SERVER_STORE_PWD | \ + keytool \ + -gencert \ + -alias $ROOT_KEY_ALIAS \ + -keystore $SERVER_STORE \ + -storepass $SERVER_STORE_PWD \ + -storetype $STORETYPE \ + -validity $VALIDITY | \ + keytool \ + -importcert \ + -alias $BOOTSTRAP_ALIAS \ + -keystore $SERVER_STORE \ + -storepass $SERVER_STORE_PWD + + +echo +echo "${H1}Client Keystore : ${RESET}" +echo "${H1}==================${RESET}" +echo "${H2}Creating client key and self-signed certificate with expected CN...${RESET}" +keytool \ + -genkeypair \ + -alias $CLIENT_ALIAS \ + -keyalg EC \ + -dname "CN=$CLIENT_SELF_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ + -validity $VALIDITY \ + -storetype $STORETYPE \ + -keypass $CLIENT_STORE_PWD \ + -keystore $CLIENT_STORE \ + -storepass $CLIENT_STORE_PWD +keytool \ + -exportcert \ + -alias $CLIENT_ALIAS \ + -keystore $CLIENT_STORE \ + -storepass $CLIENT_STORE_PWD | \ + keytool \ + -importcert \ + -alias $CLIENT_SELF_ALIAS \ + -keystore $CLIENT_STORE \ + -storepass $CLIENT_STORE_PWD \ + -noprompt + +echo +echo "${H2}Import root certificate just to be able to import ned by root CA with expected CN...${RESET}" +keytool \ + -exportcert \ + -alias $ROOT_KEY_ALIAS \ + -keystore $SERVER_STORE \ + -storepass $SERVER_STORE_PWD | \ + keytool \ + -importcert \ + -alias $ROOT_KEY_ALIAS \ + -keystore $CLIENT_STORE \ + -storepass $CLIENT_STORE_PWD \ + -noprompt + +echo +echo "${H2}Creating client certificate signed by root CA with expected CN...${RESET}" +keytool \ + -certreq \ + -alias $CLIENT_ALIAS \ + -dname "CN=$CLIENT_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ + -keystore $CLIENT_STORE \ + -storepass $CLIENT_STORE_PWD | \ + keytool \ + -gencert \ + -alias $ROOT_KEY_ALIAS \ + -keystore $SERVER_STORE \ + -storepass $SERVER_STORE_PWD \ + -storetype $STORETYPE \ + -validity $VALIDITY | \ + keytool \ + -importcert \ + -alias $CLIENT_ALIAS \ + -keystore $CLIENT_STORE \ + -storepass $CLIENT_STORE_PWD \ + -noprompt + +echo +echo "${H0}!!! Warning ${H2}Migrate ${H1}${SERVER_STORE} ${H2}to ${H1}PKCS12 ${H2}which is an industry standard format..${RESET}" +keytool \ + -importkeystore \ + -srckeystore $SERVER_STORE \ + -destkeystore $SERVER_STORE \ + -deststoretype pkcs12 \ + -srcstorepass $SERVER_STORE_PWD + +echo +echo "${H0}!!! Warning ${H2}Migrate ${H1}${CLIENT_STORE} ${H2}to ${H1}PKCS12 ${H2}which is an industry standard format..${RESET}" +keytool \ + -importkeystore \ + -srckeystore $CLIENT_STORE \ + -destkeystore $CLIENT_STORE \ + -deststoretype pkcs12 \ + -srcstorepass $CLIENT_STORE_PWD diff --git a/common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_keygen.properties b/common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_keygen.properties new file mode 100644 index 0000000000..8dd2c30a9a --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_keygen.properties @@ -0,0 +1,58 @@ +# +# Copyright © 2016-2017 The Thingsboard Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Keystore common parameters +ROOT_KEY_ALIAS=rootCA +DOMAIN_SUFFIX="$(hostname)" +ROOT_CN="$DOMAIN_SUFFIX rootCA" +ORGANIZATIONAL_UNIT=Thingsboard +ORGANIZATION=Thingsboard +CITY=SF +STATE_OR_PROVINCE=CA +TWO_LETTER_COUNTRY_CODE=US +VALIDITY=36500 #days +STORETYPE="JKS" + +#Server +SERVER_STORE=serverKeyStore.jks +SERVER_STORE_PWD=server_ks_password +SERVER_ALIAS=server +SERVER_CN="$DOMAIN_SUFFIX server LwM2M signed by root CA" +SERVER_SELF_ALIAS=server_self_signed +SERVER_SELF_CN="$DOMAIN_SUFFIX server LwM2M self-signed" +BOOTSTRAP_ALIAS=bootstrap +BOOTSTRAP_CN="$DOMAIN_SUFFIX bootstrap server LwM2M signed by root CA" +BOOTSTRAP_SELF_ALIAS=bootstrap_self_signed +BOOTSTRAP_SELF_CN="$DOMAIN_SUFFIX bootstrap server LwM2M self-signed" + +# Client +CLIENT_STORE=clientKeyStore.jks +CLIENT_STORE_PWD=client_ks_password +CLIENT_ALIAS=client +#CLIENT_CN=client_lwm2m_x509 +CLIENT_CN=mobile_lwm2m_x509 +CLIENT_SELF_ALIAS=client_self_signed +CLIENT_SELF_CN="$DOMAIN_SUFFIX client LwM2M self-signed" + +# Color output stuff +red=`tput setaf 1` +green=`tput setaf 2` +blue=`tput setaf 4` +bold=`tput bold` +H0=${red}${bold} +H1=${green}${bold} +H2=${blue} +RESET=`tput sgr0` diff --git a/common/transport/lwm2m/src/main/resources/models/10241.xml b/common/transport/lwm2m/src/main/resources/models/10241.xml new file mode 100644 index 0000000000..2b2af520e2 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10241.xml @@ -0,0 +1,81 @@ + + + + + HostDeviceInfo + + 10241 + urn:oma:lwm2m:x:10241 + + + Multiple + Optional + + Host Device Manufacturer + R + Multiple + Mandatory + String + + + + + Host Device Model Number + R + Multiple + Mandatory + String + + + + + Host Device Unique ID + R + Multiple + Mandatory + String + + + + + Host Device Software Version + R + Multiple + Mandatory + String + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10242.xml b/common/transport/lwm2m/src/main/resources/models/10242.xml new file mode 100644 index 0000000000..09a62806d3 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10242.xml @@ -0,0 +1,659 @@ + + + + + + + 3-Phase Power Meter + + + + 10242 + urn:oma:lwm2m:x:10242 + 1.0 + 1.0 + Multiple + Optional + + + Manufacturer + R + Single + Optional + String + + + + + + + + Model Number + R + Single + Optional + String + + + + + + + + Serial Number + R + Single + Optional + String + + + + + + + + Description + R + Single + Optional + String + + + + + + + + Tension R + R + Single + Mandatory + Float + + V + + + + + + Current R + R + Single + Mandatory + Float + + A + + + + + + Active Power R + R + Single + Optional + Float + + kW + + + + + + Reactive Power R + R + Single + Optional + Float + + kvar + + + + + + Inductive Reactive Power R + R + Single + Optional + Float + + kvar + + + + + + Capacitive Reactive Power R + R + Single + Optional + Float + + kvar + + + + + + Apparent Power R + R + Single + Optional + Float + + kVA + + + + + + Power Factor R + R + Single + Optional + Float + -1..1 + + + + + + + THD-V R + R + Single + Optional + Float + + /100 + + + + + + THD-A R + R + Single + Optional + Float + + /100 + + + + + + Tension S + R + Single + Mandatory + Float + + V + + + + + + Current S + R + Single + Mandatory + Float + + A + + + + + + Active Power S + R + Single + Optional + Float + + kW + + + + + + Reactive Power S + R + Single + Optional + Float + + kvar + + + + + + Inductive Reactive Power S + R + Single + Optional + Float + + kvar + + + + + + Capacitive Reactive Power S + R + Single + Optional + Float + + kvar + + + + + + Apparent Power S + R + Single + Optional + Float + + kVA + + + + + + Power Factor S + R + Single + Optional + Float + -1..1 + + + + + + + THD-V S + R + Single + Optional + Float + + /100 + + + + + + THD-A S + R + Single + Optional + Float + + /100 + + + + + + Tension T + R + Single + Mandatory + Float + + V + + + + + + Current T + R + Single + Mandatory + Float + + A + + + + + + Active Power T + R + Single + Optional + Float + + kW + + + + + + Reactive Power T + R + Single + Optional + Float + + kvar + + + + + + Inductive Reactive Power T + R + Single + Optional + Float + + kvar + + + + + + Capacitive Reactive Power T + R + Single + Optional + Float + + kvar + + + + + + Apparent Power T + R + Single + Optional + Float + + kVA + + + + + + Power Factor T + R + Single + Optional + Float + -1..1 + + + + + + + THD-V T + R + Single + Optional + Float + + /100 + + + + + + THD-A T + R + Single + Optional + Float + + /100 + + + + + + 3-Phase Active Power + R + Single + Optional + Float + + kW + + + + + + 3-Phase Reactive Power + R + Single + Optional + Float + + kvar + + + + + + 3-Phase Inductive Reactive Power + R + Single + Optional + Float + + kvar + + + + + + 3-Phase Capacitive Reactive Power + R + Single + Optional + Float + + kvar + + + + + + 3-Phase Apparent Power + R + Single + Optional + Float + + kVA + + + + + + 3-Phase Power Factor + R + Single + Optional + Float + -1..1 + + + + + + + 3-Phase phi cosine + R + Single + Optional + Float + -1..1 + + + + + + + Active Energy + R + Single + Optional + Float + + kWh + + + + + + Reactive Energy + R + Single + Optional + Float + + kvarh + + + + + + Inductive Reactive Energy + R + Single + Optional + Float + + kvarh + + + + + + Capacitive Reactive Energy + R + Single + Optional + Float + + kvarh + + + + + + Apparent Energy + R + Single + Optional + Float + + kVAh + + + + + + Tension R-S + R + Single + Optional + Float + + V + + + + + + Tension S-T + R + Single + Optional + Float + + V + + + + + + Tension T-R + R + Single + Optional + Float + + V + + + + + + Frequency + R + Single + Optional + Float + + Hz + + + + + + Neutral Current + R + Single + Optional + Float + + A + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10243.xml b/common/transport/lwm2m/src/main/resources/models/10243.xml new file mode 100644 index 0000000000..b506162174 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10243.xml @@ -0,0 +1,263 @@ + + + + + + + Single-Phase Power Meter + + + + 10243 + urn:oma:lwm2m:x:10243 + 1.0 + 1.0 + Multiple + Optional + + + Manufacturer + R + Single + Optional + String + + + + + + + + Model Number + R + Single + Optional + String + + + + + + + + Serial Number + R + Single + Optional + String + + + + + + + + Description + R + Single + Optional + String + + + + + + + + Tension + R + Single + Mandatory + String + + V + + + + + + Current + R + Single + Mandatory + Float + + A + + + + + + Active Power + R + Single + Optional + Float + + kW + + + + + + Reactive Power + R + Single + Optional + Float + + kvar + + + + + + Inductive Reactive Power + R + Single + Optional + Float + + kvar + + + + + + Capacitive Reactive Power + R + Single + Optional + Float + + kvar + + + + + + Apparent Power + R + Single + Optional + Float + + kVA + + + + + + Power Factor + R + Single + Optional + Float + -1..1 + + + + + + + THD-V + R + Single + Optional + Float + + /100 + + + + + + THD-A + R + Single + Optional + Float + + /100 + + + + + + Active Energy + R + Single + Optional + Float + + kWh + + + + + + Reactive Energy + R + Single + Optional + Float + + kvarh + + + + + + Apparent Energy + R + Single + Optional + Float + + kVAh + + + + + + Frequency + R + Single + Optional + Float + + Hz + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10244.xml b/common/transport/lwm2m/src/main/resources/models/10244.xml new file mode 100644 index 0000000000..d1ae9d911e --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10244.xml @@ -0,0 +1,301 @@ + + + VehicleControlUnit + + 10244 + urn:oma:lwm2m:x:10244 + Single + Optional + + Vehicle UI State + R + Single + Mandatory + Integer + 0..15 + + + + Vehicle Speed + R + Single + Mandatory + Integer + + km/h + + + Vehicle Shift Status + R + Single + Mandatory + Integer + 0..3 + + + + Vehicle AP Position + R + Single + Mandatory + Integer + 0..100 + /100 + + + Vehicle Power + R + Single + Optional + Float + + kW + + + Vehicle Drive Energy + R + Single + Optional + Float + + Wh + + + Vehicle Energy Consumption Efficiency + R + Single + Optional + Float + + Wh/km + + + Vehicle Estimated Mileage + R + Single + Optional + Integer + + km + + + Vehicle Charge Cable Status + R + Single + Mandatory + Boolean + + + + + Vehicle Charge Status + R + Single + Mandatory + Integer + 0..15 + + + + Vehicle Charge Voltage + R + Single + Mandatory + Float + + V + + + Vehicle Charge Current + R + Single + Mandatory + Float + + A + + + Vehicle Charge Remaining Time + R + Single + Mandatory + Integer + + min + + + Battery Pack Voltage + R + Single + Mandatory + Float + + V + + + Battery Pack Current + R + Single + Mandatory + Float + + A + + + Battery Pack Remaining Capacity + R + Single + Mandatory + Integer + + Ah + + + Battery Pack SOC + R + Single + Mandatory + Integer + 0..100 + /100 + + + Battery Pack SOH + R + Single + Mandatory + Integer + 0..100 + /100 + + + Battery Cell MinVolt + R + Single + Mandatory + Integer + + mV + + + Battery Cell MaxVolt + R + Single + Mandatory + Integer + + mV + + + Battery Module MinTemp + R + Single + Mandatory + Integer + + Cel + + + Battery Module MaxTemp + R + Single + Mandatory + Integer + + Cel + + + Battery Connection Status + R + Single + Mandatory + Boolean + + + + + + MCU Voltage + R + Single + Mandatory + Integer + + V + + + MCU Temperature + R + Single + Mandatory + Integer + + Cel + + + Motor Speed + R + Single + Mandatory + Integer + + 1/min + + + Motor Temperature + R + Single + Mandatory + Integer + + Cel + + + Motor OT Warning + R + Single + Optional + Boolean + + + + + MCU OT Warning + R + Single + Optional + Boolean + + + + + Battery Pack OT Warning + R + Single + Optional + Boolean + + + + + MCU fault + R + Single + Optional + Boolean + + + + + Motor Error + R + Single + Optional + Boolean + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10245.xml b/common/transport/lwm2m/src/main/resources/models/10245.xml new file mode 100644 index 0000000000..ca8c9da9ae --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10245.xml @@ -0,0 +1,217 @@ + + + + + + Relay Management + This LWM2M Object provides a range of eNB related measurements and parameters of which several are changeable. Furthermore, it includes Resources to enable/disable the eNB. + 10245 + urn:oma:lwm2m:x:10245 + + + Single + Optional + + + eNB Availability + R + Single + Mandatory + Boolean + AVAILABLE; UNAVAILABLE + + This field indicates to the CCC whether or not the eNB of the CrowdBox is available for activation: AVAILABLE = TRUE; UNAVAILABLE = FALSE This is set by the CrowdBox itself using an algorithm specific to the use case and based on parameters known to the CrowdBox which may not necessarily be signalled to the network. In the absence of a more specific algorithm, this parameter should be set to AVAILABLE, unless a fault is detected which would prevent activation of the eNB, in which case it should be set to UNAVAILABLE. + + + GPS Status + R + Single + Mandatory + Boolean + UNSYNCHRONISED; SYNCHRONISED + + States whether the CrowdBox GPS receiver is synchronised to GPS time or not: UNSYCHRONISED = FALSE; SYNCHRONISED = TRUE If more than one GPS receiver is used by the CrowdBox, then SYNCHRONISED should be reported only if all receivers are synchronised. + + + Orientation + R + Single + Optional + Integer + -180..180 + deg + Orientation of CrowdBox with respect to magnetic north. The reference orientation of the CrowdBox shall be the pointing direction of the eNB antenna(s) or, in the case of an omni-directional CrowdBox antenna, as defined in the accompanying product documentation. + + + eNB EARFCN + RW + Single + Mandatory + Integer + 0..65535 + + EARFCN currently used by the eNB. Highest valid value in 3GPP is currently 46589. If the requested EARFCN is not supported by the eNB, the response should be "Bad Request". The CrowdBox shall only apply a change of this resource upon execution of the “Enable eNB” command. + + + eNB Bandwidth + RW + Single + Mandatory + Integer + 5, 10, 15, 20 + + Bandwidth of the currently used eNB carrier. If the requested bandwidth is not supported by the eNB, the response should be "Bad Request". The CrowdBox shall only apply a change of this resource upon execution of the “Enable eNB” command. + + + Backhaul Primary EARFCN + RW + Single + Mandatory + Integer + 0..65535 + + EARFCN of primary cell used for the backhaul. If the requested EARFCN is not supported by the CrowdBox UE, the response should be "Bad Request". The CrowdBox shall only apply a change of this resource upon execution of the “Enable eNB” command. + + + Backhaul Secondary EARFCN + RW + Multiple + Mandatory + Integer + 0..65535 + + EARFCN of any secondary cells used for the backhaul, in the event that carrier aggregation is being used. If the requested EARFCN is not supported by the CrowdBox UE, the response should be "Bad Request". The CrowdBox shall only apply a change of this resource upon execution of the “Enable eNB” command. + + + Cumulative Measurement Window + RW + Single + Mandatory + Integer + 0..65535 + s + The current measurement interval over which cumulative statistics are collected for the following resources: Cumulative Number of Unique Users, Cumulative Downlink Throughput per Connected User, Cumulative Uplink Throughput per Connected User. Note that this measurement period is a sliding window rather than a granularity period. Measurements should never be reset, but rather old measurements should be removed from the cumulative total as they fall outside of the window. A value of 0 shall be interpreted as meaning only the current value should be reported. A value of 65535 shall be interpreted as an infinite window size (i.e. old measurements are never discarded). + + + eNB ECI + R + Single + Mandatory + Integer + 0..2^28-1 + + A 28 bit E-UTRAN Cell Identifier (ECI) + + + eNB Status + RW + Single + Mandatory + Boolean + + + This resource indicates the current status of the eNB and can be used by the CCC to change the state from enabled to disabled. TRUE = eNB enabled FALSE = eNB disabled + + + Enable eNB + E + Single + Mandatory + + + + Enables the eNB. In addition the CrowdBox shall also update its configuration to reflect the current state of other relevant parameters. This might require a reboot. + + + eNB Maximum Power + RW + Single + Mandatory + Integer + 0..63 + dBm + Maximum power for the eNB measured as the sum of input powers to all antenna connectors. The maximum power per antenna port is equal to the maximum eNB power divided by the number of antenna ports. If the requested power is above or below the maximum or minimum power levels of the eNB, then the power level should be set to the maximum or minimum respectively. The CrowdBox shall only apply a change of this resource upon execution of the “Enable eNB” command. + + + Backhaul Primary q-OffsetFreq + RW + Single + Mandatory + Integer + -24..24 + dB + q-OffsetFreq parameter for the backhaul primary EARFCN in SIB5 of the CrowdBox eNB BCCH. See TS 36.331 for details. Range: dB-24; dB-22 .. dB24 The CrowdBox shall only apply a change of this resource upon execution of the “Enable eNB” command. + + + Backhaul Secondary q-OffsetFreq + RW + Multiple + Mandatory + Integer + -24..24 + dB + q-OffsetFreq parameter for the backhaul secondary EARFCN in SIB5 of the CrowdBox eNB BCCH. See TS 36.331 for details Range: dB-24; dB-22 .. dB24 The CrowdBox shall only apply a change of this resource upon execution of the “Enable eNB” command. + + + Neighbour CrowdBox EARFCN + RW + Multiple + Mandatory + Integer + 0..66635 + + EARFCN of a neighbour CrowdBox. Each instance of this resource relates to the same instance of resource ID 15. + + + Neighbour CrowdBox q-OffsetFreq + RW + Multiple + Mandatory + Integer + -24..24 + dB + q-OffsetFreq parameter of the Neighbour CrowdBox EARFCN in SIB5 of the Neighbour CrowdBox eNB BCCH. See TS 36.331 for details Range: dB-24; dB-22 .. dB24 Each instance of this resource relates to the same instance of resource ID 14. The CrowdBox shall only apply a change of this resource upon execution of the “Enable eNB” command. + + + Serving Macro eNB cellIndividualOffset + RW + Single + Mandatory + Integer + -24..24 + dB + Specifies the value of the cellIndividualOffset parameter applicable to the CrowdBox macro serving cell that is to be signalled to connected UEs in their measurement configuration information . See TS 36.331 for details. The CrowdBox shall only apply a change of this resource upon execution of the “Enable eNB” command. + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10246.xml b/common/transport/lwm2m/src/main/resources/models/10246.xml new file mode 100644 index 0000000000..b1667af963 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10246.xml @@ -0,0 +1,108 @@ + + + + + + + CrowdBox Measurements + This LWM2M Object provides CrowdBox-related measurements such as serving cell parameters, backhaul timing advance, and neighbour cell reports. + 10246 + urn:oma:lwm2m:x:10246 + + + Single + Optional + + + Serving Cell ID + R + Single + Mandatory + Integer + 0..2^32-1 + + Serving cell ID as specified by the cellIdentity field broadcast in SIB1 of the serving cell (see TS 36.331). + + + Serving Cell RSRP + R + Single + Mandatory + Integer + 0..97 + + Serving cell RSRP, as defined in TS 36.133, Section 9.1.4. Range: RSRP_00; RSRP_01 .. RSRP_97 + + + Serving Cell RSRQ + R + Single + Mandatory + Integer + -30..46 + + Serving cell RSRQ, as defined in TS 36.133, Section 9.1.7. Range: RSRQ_-30; RSRQ_-29 .. RSRQ_46 + + + Serving Cell SINR + R + Single + Mandatory + Integer + -10..30 + dB + SINR of serving cell as estimated by the CrowdBox. Note that this is a proprietary measurement dependent on the UE chipset manufacturer. The UE chipset used should be stated in the accompanying product documentation. + + + Cumulative Backhaul Timing Advance + R + Single + Optional + Integer + 0..65535 + + The cumulative timing advance signalled by the current serving cell to the CrowdBox. This is the sum of the initial timing advance signalled in the MAC payload of the Random Access Response (11 bits, 0 .. 1282) and subsequent adjustments signalled in the MAC PDU of DL-SCH transmissions (6 bits, -31 .. 32). See TS 36.321 for details. + + + Neighbour Cell Report + R + Multiple + Mandatory + Objlnk + + + A link to the "Neighbour Cell Report" object for each neighbour cell of the CrowdBox. + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10247.xml b/common/transport/lwm2m/src/main/resources/models/10247.xml new file mode 100644 index 0000000000..17f2f51be2 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10247.xml @@ -0,0 +1,98 @@ + + + + + + + Neighbour Cell Report + This LWM2M Object provides the neighbour cell report. The CrowdBox Measurements Object and the Connected UE Report Object have both Objlnk Resources pointing to this Object. + 10247 + urn:oma:lwm2m:x:10247 + + + Multiple + Optional + + + Neighbour PCI + R + Single + Mandatory + Integer + 0..503 + + Physical Cell ID of neighbouring LTE cell, as defined in TS 36.211 + + + Neighbour Cell ID + R + Single + Optional + Integer + 0..2^32-1 + + Neighbour cell ID as specified by the cellIdentity field broadcast in SIB1 of the neighbour cell (see TS 36.331). + + + Neighbour Cell Rank + R + Single + Mandatory + Integer + 0..255 + + Current neighbour cell rank. Neighbour cells should be ordered (ranked) by the CrowdBox according to neighbour cell RSRP, with a higher RSRP corresponding to a lower index. Hence the neighbouring cell with the highest RSRP should be neighbour cell 0, the second neighbour cell 1, and so on. + + + Neighbour Cell RSRP + R + Single + Mandatory + Integer + 0..97 + + Neighbour cell RSRP, as defined in TS 36.133, Section 9.1.4. Range: RSRP_00; RSRP_01 .. RSRP_97 + + + Neighbour Cell RSRQ + R + Single + Mandatory + Integer + -30..46 + + Neighbour cell RSRQ, as defined in TS 36.133, Section 9.1.7. Range: RSRQ_-30; RSRQ_-29 .. RSRQ_46 + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10248.xml b/common/transport/lwm2m/src/main/resources/models/10248.xml new file mode 100644 index 0000000000..92f2a0a284 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10248.xml @@ -0,0 +1,78 @@ + + + + + + + Connected UE Measurements + This LWM2M Object provides a range of measurements of connected UEs and provides an Object link to the Connected UE report. + 10248 + urn:oma:lwm2m:x:10248 + + + Single + Optional + + + Number of Connected Users + R + Single + Mandatory + Integer + 0..255 + + The number of different UEs currently connected to the eNB (i.e. in RRC_CONNECTED state). + + + Cumulative Number of Unique Users + R + Single + Mandatory + Integer + 0..65535 + + The number of different UEs that have connected to the eNB over the immediately preceding period specified by the "Cumulative Measurement Window" field. + + + Connected UE Report + R + Multiple + Mandatory + Objlnk + + + Provides an Object link to the Connected UE Report which provides a range of information related to the connected UEs. + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10249.xml b/common/transport/lwm2m/src/main/resources/models/10249.xml new file mode 100644 index 0000000000..ee9e5a9d5a --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10249.xml @@ -0,0 +1,138 @@ + + + + + + + Connected UE Report + This LWM2M Object provides a range of information related to the connected UEs. + 10249 + urn:oma:lwm2m:x:10249 + + + Multiple + Optional + + + Connected User MMEC + R + Single + Mandatory + Integer + 0..255 + + MMEC signalled by the UE to the eNB in the RRCConnectionRequest message (see TS 36.331). + + + Connected User M-TMSI + R + Single + Mandatory + Integer + 0..2^32-1 + + M-TMSI signalled by the UE to the eNB in the RRCConnectionRequest message (see TS 36.331). + + + Serving Cell (CrowdBox) eNB RSRP + R + Single + Mandatory + Integer + 0..97 + + The RSRP of the CrowdBox eNB, as defined in TS 36.133, Section 9.1.4. Range: RSRP_00; RSRP_01 .. RSRP_97 + + + Serving Cell (CrowdBox) eNB RSRQ + R + Single + Mandatory + Integer + -30..46 + + The RSRQ of the CrowdBox eNB, as defined in TS 36.133, Section 9.1.7. Range: RSRQ_-30; RSRQ_-29 .. RSRQ_46 + + + Cumulative Timing Advance per Connected User + R + Single + Optional + Integer + 0..65535 + + The cumulative timing advance signalled by the eNB to each currently connected UE. This is the sum of the initial timing advance signalled in the MAC payload of the Random Access Response (11 bits, 0 .. 1282) and subsequent adjustments signalled in the MAC PDU of DL-SCH transmissions (6 bits, -31 .. 32). See TS 36.321 for details. + + + Last downlink CQI report per Connected User + R + Single + Mandatory + Integer + 0..255 + + The last downlink wideband CQI reported by a connected user the eNB. The CQI format is defined in Table 7.2.3-1 of TS 36.213. + + + Cumulative Downlink Throughput per Connected User + R + Single + Mandatory + Integer + 0..2^32-1 + B + The total number of MAC bytes sent to the connected user over the immediately preceding period specified by the "Cumulative Measurement Window" field. + + + Cumulative Uplink Throughput per Connected User + R + Single + Mandatory + Integer + 0..2^32-1 + B + The total number of MAC bytes received from the connected user over the immediately preceding period specified by the "Cumulative Measurement Window" field. + + + Neighbour Cell Report + R + Multiple + Mandatory + Objlnk + + + A link to the "Neighbour Cell Report" object for each neighbour cell reported to the CrowdBox by the connected UE + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10250.xml b/common/transport/lwm2m/src/main/resources/models/10250.xml new file mode 100644 index 0000000000..a29eda5005 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10250.xml @@ -0,0 +1,70 @@ + + + + + App Data Container + + 10250 + urn:oma:lwm2m:x:10250 + 1.0 + 1.0 + Single + Optional + + + UL data + R + Single + Mandatory + Opaque + + + + + + + + DL data + W + Single + Mandatory + Opaque + + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10251.xml b/common/transport/lwm2m/src/main/resources/models/10251.xml new file mode 100644 index 0000000000..3fb1c00154 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10251.xml @@ -0,0 +1,96 @@ + + + + + + AT Command + + 10251 + urn:oma:lwm2m:x:10251 + 1.0 + 1.0 + Multiple + Optional + + + Command + RW + Single + Mandatory + String + + + + + + Response + R + Multiple + Mandatory + String + + + + + + Status + R + Multiple + Mandatory + String + + + + + + Timeout + RW + Single + Optional + Integer + + + + + + Run + E + Single + Mandatory + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10252.xml b/common/transport/lwm2m/src/main/resources/models/10252.xml new file mode 100644 index 0000000000..ddaf7cb1f2 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10252.xml @@ -0,0 +1,229 @@ + + + + + Manifest + + 10252 + urn:oma:lwm2m:x:10252 + 1.0 + 1.0 + Single + Optional + + + Manifest + W + Single + Mandatory + Opaque + + + + + + + + State + R + Single + Mandatory + Integer + 0..8 + + + + + + Manifest Result + R + Single + Mandatory + Integer + 0..19 + + + + + + Payload Result + R + Single + Mandatory + Opaque + + + + + + + + Asset Hash + R + Single + Mandatory + Opaque + + + + + + + + Manifest version + R + Single + Mandatory + Integer + + + + + + + + Asset Installation Progress + R + Single + Mandatory + Integer + + + + + + + + Campaign Id + RW + Single + Mandatory + String + + + + + + + + Manual Trigger + E + Single + Mandatory + + + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10253.xml b/common/transport/lwm2m/src/main/resources/models/10253.xml new file mode 100644 index 0000000000..27da37d16a --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10253.xml @@ -0,0 +1,72 @@ + + + + + + + Confidential Data + + 10253 + urn:oma:lwm2m:x:10253 + 1.0 + 1.0 + Single + Optional + + + Public Key + RW + Single + Mandatory + Opaque + + + + + + + + Application Data + R + Single + Mandatory + Opaque + + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10254.xml b/common/transport/lwm2m/src/main/resources/models/10254.xml new file mode 100644 index 0000000000..706e1470aa --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10254.xml @@ -0,0 +1,119 @@ + + + + + Current Loop Input + + 10254 + urn:oma:lwm2m:x:10254:1.0 + 1.0 + 1.0 + Multiple + Optional + + + Current Loop Input Current Value + R + Single + Mandatory + Float + 0; 3.8-20.5 + mA + + + + Min Measured Value + R + Single + Optional + Float + + + + + + Max Measured Value + R + Single + Optional + Float + + + + + + Min Range Value + R + Single + Optional + Float + + + + + + Max Range Value + R + Single + Optional + Float + + + + + + Reset Min and Max Measured Values + E + Single + Optional + + + + + + + Sensor Units + R + Single + Optional + String + + + + + + Application Type + RW + Single + Optional + String + + + + + + Current Calibration + RW + Single + Optional + Float + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10255.xml b/common/transport/lwm2m/src/main/resources/models/10255.xml new file mode 100644 index 0000000000..fd63016952 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10255.xml @@ -0,0 +1,165 @@ + + + + + Device Metadata + + 10255 + urn:oma:lwm2m:x:10255 + 1.0 + 1.0 + Single + Optional + + + Protocol supported + R + Single + Mandatory + Integer + + + + + + + + Bootloader hash + R + Single + Mandatory + Opaque + + + + + + + + OEM bootloader hash + R + Single + Mandatory + Opaque + + + + + + + + Vendor + R + Single + Mandatory + String + + + + + + + + Class + R + Single + Mandatory + String + + + + + + + + Device + R + Single + Mandatory + String + + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10256.xml b/common/transport/lwm2m/src/main/resources/models/10256.xml new file mode 100644 index 0000000000..77d49f223e --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10256.xml @@ -0,0 +1,117 @@ + + + + ECID-Signal Measurement Information + + 10256 + urn:oma:lwm2m:x:10256 + 1.0 + 1.0 + Multiple + Optional + + + physCellId + R + Single + Mandatory + Integer + + + + + + + + ECGI + R + Single + Optional + Integer + + + + + + + + arfcnEUTRA + R + Single + Mandatory + Integer + + + + + + + + rsrp-Result + R + Single + Mandatory + Integer + + + + + + + + rsrq-Result + R + Single + Optional + Integer + + + + + + + + ue-RxTxTimeDiff + R + Single + Optional + Integer + + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10257.xml b/common/transport/lwm2m/src/main/resources/models/10257.xml new file mode 100644 index 0000000000..64c26f5908 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10257.xml @@ -0,0 +1,275 @@ + + + + Heat / Cooling meter + + 10257 + urn:oma:lwm2m:x:10257 + 1.0 + 1.0 + Multiple + Optional + + + Manufacturer + R + Single + Optional + String + + + + + + Model Number + R + Single + Optional + String + + + + + + Serial Number + R + Single + Optional + String + + + + + + Description + R + Single + Optional + String + + + + + + Error code + R + Multiple + Optional + Integer + + + + + + + Instantaneous active power + R + Single + Optional + Float + + W + + + + Max Measured active power + R + Multiple + Mandatory + Float + + W + + + + Cumulative active power + R + Single + Optional + Float + + Wh + + + + Flow temperature + R + Single + Optional + Float + + Cel + + + + Max Measured flow temperature + R + Single + Optional + Float + + Cel + + + + Return temperature + R + Single + Optional + Float + + Cel + + + + Max Measured return temperature + R + Single + Optional + Float + + Cel + + + + Temperature difference + R + Single + Optional + Float + + K + + + + Flow rate + R + Single + Optional + Float + + m3/s + + + + Max Measured flow + R + Single + Optional + Float + + m3/s + + + + Flow volume + R + Single + Optional + Float + + m3 + + + + Return volume + R + Single + Optional + Float + + m3 + + + + Current Time + RW + Single + Optional + Time + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10258.xml b/common/transport/lwm2m/src/main/resources/models/10258.xml new file mode 100644 index 0000000000..3fbf7c7c54 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10258.xml @@ -0,0 +1,89 @@ + + + + + Current Loop Output + + 10258 + urn:oma:lwm2m:x:10258 + 1.0 + 1.0 + Multiple + Optional + + + Current Loop Output Current Value + RW + Single + Mandatory + Float + 3.8-20.5 + mA + + + + Min Range Value + R + Single + Optional + Float + + + + + + Max Range Value + R + Single + Optional + Float + + + + + + Sensor Units + R + Single + Optional + String + + + + + + Application Type + RW + Single + Optional + String + + + + + + Current Calibration + RW + Single + Optional + Float + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10259.xml b/common/transport/lwm2m/src/main/resources/models/10259.xml new file mode 100644 index 0000000000..d75869a122 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10259.xml @@ -0,0 +1,115 @@ + + + + + + + System Log + + 10259 + urn:oma:lwm2m:x:10259 + 1.0 + 1.0 + Multiple + Optional + + + Name + R + Single + Mandatory + String + + + + + + + + Read All + R + Single + Mandatory + String + + + + + + + + Read + R + Single + Optional + String + + + + + + + + Enabled + RW + Single + Optional + Boolean + + + + + + + + Capture Level + RW + Single + Optional + Integer + + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10260-2_0.xml b/common/transport/lwm2m/src/main/resources/models/10260-2_0.xml new file mode 100644 index 0000000000..5cd084af73 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10260-2_0.xml @@ -0,0 +1,95 @@ + + + + + + RDB + + 10260 + urn:oma:lwm2m:x:10260:2.0 + 1.0 + 2.0 + Multiple + Optional + + + Key + RW + Single + Mandatory + String + + + + + + + + Value + RW + Single + Optional + String + + + + + + + + Exists + RW + Single + Optional + Boolean + + + + + + + + Persistent + RW + Single + Optional + Boolean + + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10262.xml b/common/transport/lwm2m/src/main/resources/models/10262.xml new file mode 100644 index 0000000000..7b2e170c9b --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10262.xml @@ -0,0 +1,87 @@ + + + + + + + Interval Data Delivery + + 10262 + urn:oma:lwm2m:x:10262 + Multiple + Optional + + + Name + RW + Single + Mandatory + String + + + + + + Interval Data Links + RW + Multiple + Mandatory + Objlnk + + + + + + Latest Payload + R + Multiple + Mandatory + Opaque + + + + + + Schedule + RW + Single + Optional + Objlnk + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10263.xml b/common/transport/lwm2m/src/main/resources/models/10263.xml new file mode 100644 index 0000000000..5e18f44244 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10263.xml @@ -0,0 +1,90 @@ + + + + + + + Event Data Delivery + + 10263 + urn:oma:lwm2m:x:10263 + Multiple + Optional + + + Name + RW + Single + Mandatory + String + + + + + + Event Data Links + RW + Multiple + Mandatory + Objlnk + + + + + + Latest Eventlog + R + Multiple + Mandatory + Opaque + + + + + + Schedule + RW + Single + Mandatory + Objlnk + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10264.xml b/common/transport/lwm2m/src/main/resources/models/10264.xml new file mode 100644 index 0000000000..eeaad07447 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10264.xml @@ -0,0 +1,117 @@ + + + + + + + Delivery Schedule + + 10264 + urn:oma:lwm2m:x:10264 + Multiple + Optional + + + Schedule Start Time + RW + Single + Mandatory + Integer + + + + + + Schedule UTC Offset + RW + Single + Mandatory + String + + + + + + Delivery Frequency + RW + Single + Mandatory + Integer + + + + + + Randomised Delivery Window + RW + Single + Optional + Integer + + + + + + Number of Retries + RW + Single + Optional + Integer + + + + + + Retry Period + RW + Single + Optional + Integer + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10265.xml b/common/transport/lwm2m/src/main/resources/models/10265.xml new file mode 100644 index 0000000000..26657bb754 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10265.xml @@ -0,0 +1,136 @@ + + + + + + + Leakage Detection Configuration + + 10265 + urn:oma:lwm2m:x:10265 + Single + Optional + + + Sample Times + RW + Multiple + Mandatory + Integer + + + + + + Sample UTC Offset + RW + Single + Optional + String + + + + + + Detection Mode + RW + Single + Mandatory + Integer + 0..3 + + + + + Top Frequency Count + RW + Single + Optional + Integer + + + + + + Frequency Thresholds + RW + Multiple + Optional + Integer + 0..999 + + + + + Frequency Values + R + Multiple + Optional + Integer + + + + + + Firmware Version + R + Single + Mandatory + String + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10266.xml b/common/transport/lwm2m/src/main/resources/models/10266.xml new file mode 100644 index 0000000000..57f7285b84 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10266.xml @@ -0,0 +1,244 @@ + + + + + + + Water Flow Readings + + 10266 + urn:oma:lwm2m:x:10266 + Multiple + Optional + + + Interval Period + R + Single + Mandatory + Integer + 1..864000 + s + + + + Interval Start Offset + R + Single + Optional + Integer + 0..86399 + s + + + + Interval UTC Offset + R + Single + Optional + String + + + + + + Interval Collection Start Time + R + Single + Mandatory + Time + + + + + + Oldest Recorded Interval + R + Single + Mandatory + Time + + + + + + Last Delivered Interval + RW + Single + Optional + Time + + + + + + Latest Recorded Interval + R + Single + Mandatory + Time + + + + + + Interval Delivery Midnight Aligned + RW + Single + Mandatory + Boolean + + + + + + Interval Historical Read + E + Single + Optional + + + + + + + Interval Historical Read Payload + R + Single + Optional + Opaque + + + + + + Interval Change Configuration + E + Single + Optional + + + + + + + Start + E + Single + Optional + + + + + + + Stop + E + Single + Optional + + + + + + + Status + R + Single + Optional + Integer + + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10267.xml b/common/transport/lwm2m/src/main/resources/models/10267.xml new file mode 100644 index 0000000000..3c6734723f --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10267.xml @@ -0,0 +1,244 @@ + + + + + + + Daily Maximum Flow Rate Readings + + 10267 + urn:oma:lwm2m:x:10267 + Multiple + Optional + + + Interval Period + R + Single + Mandatory + Integer + 1..864000 + s + + + + Interval Start Offset + R + Single + Optional + Integer + 0..86399 + s + + + + Interval UTC Offset + R + Single + Optional + String + + + + + + Interval Collection Start Time + R + Single + Mandatory + Time + + + + + + Oldest Recorded Interval + R + Single + Mandatory + Time + + + + + + Last Delivered Interval + RW + Single + Optional + Time + + + + + + Latest Recorded Interval + R + Single + Mandatory + Time + + + + + + Interval Delivery Midnight Aligned + RW + Single + Mandatory + Boolean + + + + + + Interval Historical Read + E + Single + Optional + + + + + + + Interval Historical Read Payload + R + Single + Optional + Opaque + + + + + + Interval Change Configuration + E + Single + Optional + + + + + + + Start + E + Single + Optional + + + + + + + Stop + E + Single + Optional + + + + + + + Status + R + Single + Optional + Integer + + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10268.xml b/common/transport/lwm2m/src/main/resources/models/10268.xml new file mode 100644 index 0000000000..9a6d06262e --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10268.xml @@ -0,0 +1,244 @@ + + + + + + + Temperature Readings + + 10268 + urn:oma:lwm2m:x:10268 + Multiple + Optional + + + Interval Period + R + Single + Mandatory + Integer + 1..864000 + s + + + + Interval Start Offset + R + Single + Optional + Integer + 0..86399 + s + + + + Interval UTC Offset + R + Single + Optional + String + + + + + + Interval Collection Start Time + R + Single + Mandatory + Time + + + + + + Oldest Recorded Interval + R + Single + Mandatory + Time + + + + + + Last Delivered Interval + RW + Single + Optional + Time + + + + + + Latest Recorded Interval + R + Single + Mandatory + Time + + + + + + Interval Delivery Midnight Aligned + RW + Single + Mandatory + Boolean + + + + + + Interval Historical Read + E + Single + Optional + + + + + + + Interval Historical Read Payload + R + Single + Optional + Opaque + + + + + + Interval Change Configuration + E + Single + Optional + + + + + + + Start + E + Single + Optional + + + + + + + Stop + E + Single + Optional + + + + + + + Status + R + Single + Optional + Integer + + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10269.xml b/common/transport/lwm2m/src/main/resources/models/10269.xml new file mode 100644 index 0000000000..648227a7d7 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10269.xml @@ -0,0 +1,244 @@ + + + + + + + Pressure Readings + + 10269 + urn:oma:lwm2m:x:10269 + Multiple + Optional + + + Interval Period + R + Single + Mandatory + Integer + 1..864000 + s + + + + Interval Start Offset + R + Single + Optional + Integer + 0..86399 + s + + + + Interval UTC Offset + R + Single + Optional + String + + + + + + Interval Collection Start Time + R + Single + Mandatory + Time + + + + + + Oldest Recorded Interval + R + Single + Mandatory + Time + + + + + + Last Delivered Interval + RW + Single + Optional + Time + + + + + + Latest Recorded Interval + R + Single + Mandatory + Time + + + + + + Interval Delivery Midnight Aligned + RW + Single + Mandatory + Boolean + + + + + + Interval Historical Read + E + Single + Optional + + + + + + + Interval Historical Read Payload + R + Single + Optional + Opaque + + + + + + Interval Change Configuration + E + Single + Optional + + + + + + + Start + E + Single + Optional + + + + + + + Stop + E + Single + Optional + + + + + + + Status + R + Single + Optional + Integer + + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10270.xml b/common/transport/lwm2m/src/main/resources/models/10270.xml new file mode 100644 index 0000000000..69e3e7e5f3 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10270.xml @@ -0,0 +1,244 @@ + + + + + + + Battery Level Readings + + 10270 + urn:oma:lwm2m:x:10270 + Multiple + Optional + + + Interval Period + R + Single + Mandatory + Integer + 1..864000 + s + + + + Interval Start Offset + R + Single + Optional + Integer + 0..86399 + s + + + + Interval UTC Offset + R + Single + Optional + String + + + + + + Interval Collection Start Time + R + Single + Mandatory + Time + + + + + + Oldest Recorded Interval + R + Single + Mandatory + Time + + + + + + Last Delivered Interval + RW + Single + Optional + Time + + + + + + Latest Recorded Interval + R + Single + Mandatory + Time + + + + + + Interval Delivery Midnight Aligned + RW + Single + Mandatory + Boolean + + + + + + Interval Historical Read + E + Single + Optional + + + + + + + Interval Historical Read Payload + R + Single + Optional + Opaque + + + + + + Interval Change Configuration + E + Single + Optional + + + + + + + Start + E + Single + Optional + + + + + + + Stop + E + Single + Optional + + + + + + + Status + R + Single + Optional + Integer + + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10271.xml b/common/transport/lwm2m/src/main/resources/models/10271.xml new file mode 100644 index 0000000000..f33a3d27e6 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10271.xml @@ -0,0 +1,244 @@ + + + + + + + Communications Activity Time Readings + + 10271 + urn:oma:lwm2m:x:10271 + Multiple + Optional + + + Interval Period + R + Single + Mandatory + Integer + 1..864000 + s + + + + Interval Start Offset + R + Single + Optional + Integer + 0..86399 + s + + + + Interval UTC Offset + R + Single + Optional + String + + + + + + Interval Collection Start Time + R + Single + Mandatory + Time + + + + + + Oldest Recorded Interval + R + Single + Mandatory + Time + + + + + + Last Delivered Interval + RW + Single + Optional + Time + + + + + + Latest Recorded Interval + R + Single + Mandatory + Time + + + + + + Interval Delivery Midnight Aligned + RW + Single + Mandatory + Boolean + + + + + + Interval Historical Read + E + Single + Optional + + + + + + + Interval Historical Read Payload + R + Single + Optional + Opaque + + + + + + Interval Change Configuration + E + Single + Optional + + + + + + + Start + E + Single + Optional + + + + + + + Stop + E + Single + Optional + + + + + + + Status + R + Single + Optional + Integer + + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10272.xml b/common/transport/lwm2m/src/main/resources/models/10272.xml new file mode 100644 index 0000000000..d70236947b --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10272.xml @@ -0,0 +1,230 @@ + + + + + + + Water Meter Customer Leakage Alarm + + 10272 + urn:oma:lwm2m:x:10272 + Multiple + Optional + + + Event Type + RW + Single + Mandatory + Integer + + + + + + Alarm Realtime + RW + Single + Mandatory + Boolean + + + + + + Alarm State + R + Single + Optional + Boolean + + + + + + Alarm Set Threshold + RW + Single + Optional + Float + + + + + + Alarm Set Operator + RW + Single + Optional + Integer + + + + + + Alarm Clear Threshold + RW + Single + Optional + Float + + + + + + Alarm Clear Operator + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Count + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Period + RW + Single + Optional + Integer + 1..864000 + s + + + + Latest Delivered Event Time + RW + Single + Optional + Time + + + + + + Latest Recorded Event Time + R + Single + Mandatory + Time + + + + + + Alarm Clear + E + Single + Optional + + + + + + + Alarm Auto Clear + RW + Single + Optional + Boolean + + + + + + Event Code + R + Single + Mandatory + Integer + 100..255 + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10273.xml b/common/transport/lwm2m/src/main/resources/models/10273.xml new file mode 100644 index 0000000000..55404b38d5 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10273.xml @@ -0,0 +1,230 @@ + + + + + + + Water Meter Reverse Flow Alarm + + 10273 + urn:oma:lwm2m:x:10273 + Multiple + Optional + + + Event Type + RW + Single + Mandatory + Integer + + + + + + Alarm Realtime + RW + Single + Mandatory + Boolean + + + + + + Alarm State + R + Single + Optional + Boolean + + + + + + Alarm Set Threshold + RW + Single + Optional + Float + + + + + + Alarm Set Operator + RW + Single + Optional + Integer + + + + + + Alarm Clear Threshold + RW + Single + Optional + Float + + + + + + Alarm Clear Operator + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Count + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Period + RW + Single + Optional + Integer + 1..864000 + s + + + + Latest Delivered Event Time + RW + Single + Optional + Time + + + + + + Latest Recorded Event Time + R + Single + Mandatory + Time + + + + + + Alarm Clear + E + Single + Optional + + + + + + + Alarm Auto Clear + RW + Single + Optional + Boolean + + + + + + Event Code + R + Single + Mandatory + Integer + 100..255 + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10274.xml b/common/transport/lwm2m/src/main/resources/models/10274.xml new file mode 100644 index 0000000000..e0f9de62dc --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10274.xml @@ -0,0 +1,230 @@ + + + + + + + Water Meter Empty Pipe Alarm + + 10274 + urn:oma:lwm2m:x:10274 + Multiple + Optional + + + Event Type + RW + Single + Mandatory + Integer + + + + + + Alarm Realtime + RW + Single + Mandatory + Boolean + + + + + + Alarm State + R + Single + Optional + Boolean + + + + + + Alarm Set Threshold + RW + Single + Optional + Float + + + + + + Alarm Set Operator + RW + Single + Optional + Integer + + + + + + Alarm Clear Threshold + RW + Single + Optional + Float + + + + + + Alarm Clear Operator + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Count + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Period + RW + Single + Optional + Integer + 1..864000 + s + + + + Latest Delivered Event Time + RW + Single + Optional + Time + + + + + + Latest Recorded Event Time + R + Single + Mandatory + Time + + + + + + Alarm Clear + E + Single + Optional + + + + + + + Alarm Auto Clear + RW + Single + Optional + Boolean + + + + + + Event Code + R + Single + Mandatory + Integer + 100..255 + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10275.xml b/common/transport/lwm2m/src/main/resources/models/10275.xml new file mode 100644 index 0000000000..d0bc4dd350 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10275.xml @@ -0,0 +1,230 @@ + + + + + + + Water Meter Tamper Alarm + + 10275 + urn:oma:lwm2m:x:10275 + Multiple + Optional + + + Event Type + RW + Single + Mandatory + Integer + + + + + + Alarm Realtime + RW + Single + Mandatory + Boolean + + + + + + Alarm State + R + Single + Optional + Boolean + + + + + + Alarm Set Threshold + RW + Single + Optional + Float + + + + + + Alarm Set Operator + RW + Single + Optional + Integer + + + + + + Alarm Clear Threshold + RW + Single + Optional + Float + + + + + + Alarm Clear Operator + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Count + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Period + RW + Single + Optional + Integer + 1..864000 + s + + + + Latest Delivered Event Time + RW + Single + Optional + Time + + + + + + Latest Recorded Event Time + R + Single + Mandatory + Time + + + + + + Alarm Clear + E + Single + Optional + + + + + + + Alarm Auto Clear + RW + Single + Optional + Boolean + + + + + + Event Code + R + Single + Mandatory + Integer + 100..255 + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10276.xml b/common/transport/lwm2m/src/main/resources/models/10276.xml new file mode 100644 index 0000000000..24f0e0056a --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10276.xml @@ -0,0 +1,230 @@ + + + + + + + Water Meter High Pressure Alarm + + 10276 + urn:oma:lwm2m:x:10276 + Multiple + Optional + + + Event Type + RW + Single + Mandatory + Integer + + + + + + Alarm Realtime + RW + Single + Mandatory + Boolean + + + + + + Alarm State + R + Single + Optional + Boolean + + + + + + Alarm Set Threshold + RW + Single + Optional + Float + + + + + + Alarm Set Operator + RW + Single + Optional + Integer + + + + + + Alarm Clear Threshold + RW + Single + Optional + Float + + + + + + Alarm Clear Operator + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Count + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Period + RW + Single + Optional + Integer + 1..864000 + s + + + + Latest Delivered Event Time + RW + Single + Optional + Time + + + + + + Latest Recorded Event Time + R + Single + Mandatory + Time + + + + + + Alarm Clear + E + Single + Optional + + + + + + + Alarm Auto Clear + RW + Single + Optional + Boolean + + + + + + Event Code + R + Single + Mandatory + Integer + 100..255 + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10277.xml b/common/transport/lwm2m/src/main/resources/models/10277.xml new file mode 100644 index 0000000000..07e431b9da --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10277.xml @@ -0,0 +1,230 @@ + + + + + + + Water Meter Low Pressure Alarm + + 10277 + urn:oma:lwm2m:x:10277 + Multiple + Optional + + + Event Type + RW + Single + Mandatory + Integer + + + + + + Alarm Realtime + RW + Single + Mandatory + Boolean + + + + + + Alarm State + R + Single + Optional + Boolean + + + + + + Alarm Set Threshold + RW + Single + Optional + Float + + + + + + Alarm Set Operator + RW + Single + Optional + Integer + + + + + + Alarm Clear Threshold + RW + Single + Optional + Float + + + + + + Alarm Clear Operator + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Count + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Period + RW + Single + Optional + Integer + 1..864000 + s + + + + Latest Delivered Event Time + RW + Single + Optional + Time + + + + + + Latest Recorded Event Time + R + Single + Mandatory + Time + + + + + + Alarm Clear + E + Single + Optional + + + + + + + Alarm Auto Clear + RW + Single + Optional + Boolean + + + + + + Event Code + R + Single + Mandatory + Integer + 100..255 + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10278.xml b/common/transport/lwm2m/src/main/resources/models/10278.xml new file mode 100644 index 0000000000..9070e1c70e --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10278.xml @@ -0,0 +1,230 @@ + + + + + + + High Temperature Alarm + + 10278 + urn:oma:lwm2m:x:10278 + Multiple + Optional + + + Event Type + RW + Single + Mandatory + Integer + + + + + + Alarm Realtime + RW + Single + Mandatory + Boolean + + + + + + Alarm State + R + Single + Optional + Boolean + + + + + + Alarm Set Threshold + RW + Single + Optional + Float + + + + + + Alarm Set Operator + RW + Single + Optional + Integer + + + + + + Alarm Clear Threshold + RW + Single + Optional + Float + + + + + + Alarm Clear Operator + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Count + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Period + RW + Single + Optional + Integer + 1..864000 + s + + + + Latest Delivered Event Time + RW + Single + Optional + Time + + + + + + Latest Recorded Event Time + R + Single + Mandatory + Time + + + + + + Alarm Clear + E + Single + Optional + + + + + + + Alarm Auto Clear + RW + Single + Optional + Boolean + + + + + + Event Code + R + Single + Mandatory + Integer + 100..255 + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10279.xml b/common/transport/lwm2m/src/main/resources/models/10279.xml new file mode 100644 index 0000000000..6eef195800 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10279.xml @@ -0,0 +1,230 @@ + + + + + + + Low Temperature Alarm + + 10279 + urn:oma:lwm2m:x:10279 + Multiple + Optional + + + Event Type + RW + Single + Mandatory + Integer + + + + + + Alarm Realtime + RW + Single + Mandatory + Boolean + + + + + + Alarm State + R + Single + Optional + Boolean + + + + + + Alarm Set Threshold + RW + Single + Optional + Float + + + + + + Alarm Set Operator + RW + Single + Optional + Integer + + + + + + Alarm Clear Threshold + RW + Single + Optional + Float + + + + + + Alarm Clear Operator + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Count + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Period + RW + Single + Optional + Integer + 1..864000 + s + + + + Latest Delivered Event Time + RW + Single + Optional + Time + + + + + + Latest Recorded Event Time + R + Single + Mandatory + Time + + + + + + Alarm Clear + E + Single + Optional + + + + + + + Alarm Auto Clear + RW + Single + Optional + Boolean + + + + + + Event Code + R + Single + Mandatory + Integer + 100..255 + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10280.xml b/common/transport/lwm2m/src/main/resources/models/10280.xml new file mode 100644 index 0000000000..0fe4976077 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10280.xml @@ -0,0 +1,230 @@ + + + + + + + Water Network Leak Alarm + + 10280 + urn:oma:lwm2m:x:10280 + Multiple + Optional + + + Event Type + RW + Single + Mandatory + Integer + + + + + + Alarm Realtime + RW + Single + Mandatory + Boolean + + + + + + Alarm State + R + Single + Optional + Boolean + + + + + + Alarm Set Threshold + RW + Single + Optional + Float + + + + + + Alarm Set Operator + RW + Single + Optional + Integer + + + + + + Alarm Clear Threshold + RW + Single + Optional + Float + + + + + + Alarm Clear Operator + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Count + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Period + RW + Single + Optional + Integer + 1..864000 + s + + + + Latest Delivered Event Time + RW + Single + Optional + Time + + + + + + Latest Recorded Event Time + R + Single + Mandatory + Time + + + + + + Alarm Clear + E + Single + Optional + + + + + + + Alarm Auto Clear + RW + Single + Optional + Boolean + + + + + + Event Code + R + Single + Mandatory + Integer + 100..255 + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10281.xml b/common/transport/lwm2m/src/main/resources/models/10281.xml new file mode 100644 index 0000000000..a02a83e348 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10281.xml @@ -0,0 +1,230 @@ + + + + + + + Low Battery Alarm + + 10281 + urn:oma:lwm2m:x:10281 + Multiple + Optional + + + Event Type + RW + Single + Mandatory + Integer + + + + + + Alarm Realtime + RW + Single + Mandatory + Boolean + + + + + + Alarm State + R + Single + Optional + Boolean + + + + + + Alarm Set Threshold + RW + Single + Optional + Float + + + + + + Alarm Set Operator + RW + Single + Optional + Integer + + + + + + Alarm Clear Threshold + RW + Single + Optional + Float + + + + + + Alarm Clear Operator + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Count + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Period + RW + Single + Optional + Integer + 1..864000 + s + + + + Latest Delivered Event Time + RW + Single + Optional + Time + + + + + + Latest Recorded Event Time + R + Single + Mandatory + Time + + + + + + Alarm Clear + E + Single + Optional + + + + + + + Alarm Auto Clear + RW + Single + Optional + Boolean + + + + + + Event Code + R + Single + Mandatory + Integer + 100..255 + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10282.xml b/common/transport/lwm2m/src/main/resources/models/10282.xml new file mode 100644 index 0000000000..d7c97729b8 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10282.xml @@ -0,0 +1,230 @@ + + + + + + + Daughter Board Failure Alarm + + 10282 + urn:oma:lwm2m:x:10282 + Multiple + Optional + + + Event Type + RW + Single + Mandatory + Integer + + + + + + Alarm Realtime + RW + Single + Mandatory + Boolean + + + + + + Alarm State + R + Single + Optional + Boolean + + + + + + Alarm Set Threshold + RW + Single + Optional + Float + + + + + + Alarm Set Operator + RW + Single + Optional + Integer + + + + + + Alarm Clear Threshold + RW + Single + Optional + Float + + + + + + Alarm Clear Operator + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Count + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Period + RW + Single + Optional + Integer + 1..864000 + s + + + + Latest Delivered Event Time + RW + Single + Optional + Time + + + + + + Latest Recorded Event Time + R + Single + Mandatory + Time + + + + + + Alarm Clear + E + Single + Optional + + + + + + + Alarm Auto Clear + RW + Single + Optional + Boolean + + + + + + Event Code + R + Single + Mandatory + Integer + 100..255 + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10283.xml b/common/transport/lwm2m/src/main/resources/models/10283.xml new file mode 100644 index 0000000000..6e4df48342 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10283.xml @@ -0,0 +1,230 @@ + + + + + + + Device Reboot Event + + 10283 + urn:oma:lwm2m:x:10283 + Multiple + Optional + + + Event Type + RW + Single + Mandatory + Integer + + + + + + Alarm Realtime + RW + Single + Mandatory + Boolean + + + + + + Alarm State + R + Single + Optional + Boolean + + + + + + Alarm Set Threshold + RW + Single + Optional + Float + + + + + + Alarm Set Operator + RW + Single + Optional + Integer + + + + + + Alarm Clear Threshold + RW + Single + Optional + Float + + + + + + Alarm Clear Operator + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Count + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Period + RW + Single + Optional + Integer + 1..864000 + s + + + + Latest Delivered Event Time + RW + Single + Optional + Time + + + + + + Latest Recorded Event Time + R + Single + Mandatory + Time + + + + + + Alarm Clear + E + Single + Optional + + + + + + + Alarm Auto Clear + RW + Single + Optional + Boolean + + + + + + Event Code + R + Single + Mandatory + Integer + 100..255 + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10284.xml b/common/transport/lwm2m/src/main/resources/models/10284.xml new file mode 100644 index 0000000000..964df21df9 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10284.xml @@ -0,0 +1,230 @@ + + + + + + + Time Synchronisation Event + + 10284 + urn:oma:lwm2m:x:10284 + Multiple + Optional + + + Event Type + RW + Single + Mandatory + Integer + + + + + + Alarm Realtime + RW + Single + Mandatory + Boolean + + + + + + Alarm State + R + Single + Optional + Boolean + + + + + + Alarm Set Threshold + RW + Single + Optional + Float + + + + + + Alarm Set Operator + RW + Single + Optional + Integer + + + + + + Alarm Clear Threshold + RW + Single + Optional + Float + + + + + + Alarm Clear Operator + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Count + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Period + RW + Single + Optional + Integer + 1..864000 + s + + + + Latest Delivered Event Time + RW + Single + Optional + Time + + + + + + Latest Recorded Event Time + R + Single + Mandatory + Time + + + + + + Alarm Clear + E + Single + Optional + + + + + + + Alarm Auto Clear + RW + Single + Optional + Boolean + + + + + + Event Code + R + Single + Mandatory + Integer + 100..255 + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10286.xml b/common/transport/lwm2m/src/main/resources/models/10286.xml new file mode 100644 index 0000000000..39e0809788 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10286.xml @@ -0,0 +1,48 @@ + + + + App Fota Container + + 10286 + urn:oma:lwm2m:x:10286 + 1.0 + 1.0 + Single + Optional + + + UL data + R + Single + Mandatory + Opaque + + + + + + + + DL data + W + Single + Mandatory + Opaque + + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10290.xml b/common/transport/lwm2m/src/main/resources/models/10290.xml new file mode 100644 index 0000000000..7b89cc06c0 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10290.xml @@ -0,0 +1,198 @@ + + + + + + + Voltage Logging + + 10290 + urn:oma:lwm2m:x:10290 + 1.0 + 1.0 + Multiple + Optional + + + Interval Period + R + Single + Mandatory + Integer + 1..864000 + s + + + + Interval Start Offset + R + Single + Optional + Integer + 0..86399 + s + + + + Interval UTC Offset + R + Single + Optional + String + + + + + + Interval Collection Start Time + R + Single + Mandatory + Time + + + + + + Oldest Recorded Interval + R + Single + Mandatory + Time + + + + + + Last Delivered Interval + RW + Single + Optional + Time + + + + + + Latest Recorded Interval + R + Single + Mandatory + Time + + + + + + Interval Delivery Midnight Aligned + RW + Single + Mandatory + Boolean + + + + + + Interval Historical Read + E + Single + Optional + + + + + + + Interval Historical Read Payload + R + Single + Optional + Opaque + + + + + + Interval Change Configuration + E + Single + Optional + + + + + + + Start + E + Single + Optional + + + + + + + Stop + E + Single + Optional + + + + + + + Status + R + Single + Optional + Integer + + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10291.xml b/common/transport/lwm2m/src/main/resources/models/10291.xml new file mode 100644 index 0000000000..a232ed02f9 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10291.xml @@ -0,0 +1,208 @@ + + + + + + + Voltage Transient + + 10291 + urn:oma:lwm2m:x:10291 + 1.0 + 1.0 + Multiple + Optional + + + Interval Period + R + Single + Mandatory + Integer + 1..864000 + s + + + + Interval Start Offset + R + Single + Mandatory + Integer + 0..86399 + s + + + + Interval UTC Offset + R + Single + Optional + String + + + + + + Interval Collection Start Time + R + Single + Mandatory + Time + + + + + + Oldest Recorded Interval + R + Single + Mandatory + Time + + + + + + Last Delivered Interval + RW + Single + Mandatory + Time + + + + + + Latest Recorded Interval + R + Single + Mandatory + Time + + + + + + Interval Delivery Midnight Aligned + RW + Single + Mandatory + Boolean + + + + + + Interval Historical Read + E + Single + Optional + + + + + + + Interval Historical Read Payload + R + Single + Optional + Opaque + + + + + + Interval Change Configuration + E + Single + Optional + + + + + + + Start + E + Single + Optional + + + + + + + Stop + E + Single + Optional + + + + + + + Status + R + Single + Optional + Integer + + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + Sample Frequency + RW + Single + Mandatory + Float + 0.0..86400.0 + s + How often the inputs are read/sampled.This value can be changed by doing a write command + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10292.xml b/common/transport/lwm2m/src/main/resources/models/10292.xml new file mode 100644 index 0000000000..00fe33e320 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10292.xml @@ -0,0 +1,208 @@ + + + + + + + Pressure Transient + + 10292 + urn:oma:lwm2m:x:10292 + 1.0 + 1.0 + Multiple + Optional + + + Interval Period + R + Single + Mandatory + Integer + 1..864000 + s + + + + Interval Start Offset + R + Single + Mandatory + Integer + 0..86399 + s + + + + Interval UTC Offset + R + Single + Optional + String + + + + + + Interval Collection Start Time + R + Single + Mandatory + Time + + + + + + Oldest Recorded Interval + R + Single + Mandatory + Time + + + + + + Last Delivered Interval + RW + Single + Mandatory + Time + + + + + + Latest Recorded Interval + R + Single + Mandatory + Time + + + + + + Interval Delivery Midnight Aligned + RW + Single + Mandatory + Boolean + + + + + + Interval Historical Read + E + Single + Optional + + + + + + + Interval Historical Read Payload + R + Single + Optional + Opaque + + + + + + Interval Change Configuration + E + Single + Optional + + + + + + + Start + E + Single + Optional + + + + + + + Stop + E + Single + Optional + + + + + + + Status + R + Single + Optional + Integer + + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + Sample Frequency + RW + Single + Mandatory + Float + 0.0..86400.0 + s + How often the inputs are read/sampled.This value can be changed by doing a write command + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10299.xml b/common/transport/lwm2m/src/main/resources/models/10299.xml new file mode 100644 index 0000000000..2c4ea4d2db --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10299.xml @@ -0,0 +1,113 @@ + + + + + + + HostDevice + This LWM2M Object provides a range of host device related information which can be queried by the LWM2M Server. The host device is any integrated device with an embedded cellular radio module. + 10299 + urn:oma:lwm2m:x:10299 + 1.0 + 1.0 + Single + Optional + + + Manufacturer + R + Single + Mandatory + String + + + Host device manufacturers name (OEM). + + + Model + R + Single + Mandatory + String + + Identifier of the model name or number determined by device manufacturer. + UniqueID + R + Single + Mandatory + String + + + Unique ID assigned by an manufacturer or other body. Used to uniquely identify a host device. Examples include serial # or UUID. + + + FirmwareVersion + R + Single + Mandatory + String + + + Current Firmware version of the host device. (manufacturer specified string). + + SoftwareVersion + R + Single + Optional + String + + + Current software version of the host device. (manufacturer specified string). + + HardwareVersion + R + Single + Optional + String + + + Current hardware version of the host device. (manufacturer specified string). + + + DateStamp + R + Single + Optional + String + + + UTC value of the time and date of the last Firmware or Software update. Format:MM:DD:YYYY HH:MM:SS + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10300.xml b/common/transport/lwm2m/src/main/resources/models/10300.xml new file mode 100644 index 0000000000..b290057806 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10300.xml @@ -0,0 +1,142 @@ + + + + + + + LWM2M Meta Object + + + + 10300 + urn:oma:lwm2m:x:10300 + 1.0 + 1.0 + Multiple + Optional + + + ObjectID + R + Single + Mandatory + Integer + + + + + + + + ObjectURN + R + Single + Mandatory + String + + + + + + + + ObjectInstanceHandle + R + Single + Optional + Objlnk + + + + + + + + URI + R + Multiple + Mandatory + String + + + + + + + + SHAType + R + Single + Optional + Integer + 0..8 + + + + + + + ChecksumValue + R + Single + Optional + String + + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10308-2_0.xml b/common/transport/lwm2m/src/main/resources/models/10308-2_0.xml new file mode 100644 index 0000000000..0ed1a6ea30 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10308-2_0.xml @@ -0,0 +1,145 @@ + + + + + + + AT&T Connectivity Extension + + 10308 + urn:oma:lwm2m:x:10308:2.0 + 1.0 + 2.0 + Multiple + Optional + + + ICCID + R + Single + Mandatory + String + + + + + + + IMSI + R + Single + Mandatory + String + + + + + + + MSISDN + RW + Single + Mandatory + String + + + + + + + APN Retries + RW + Single + Mandatory + Integer + + + + + + + APN Retry Period + RW + Single + Mandatory + Integer + + + s + + + + APN Retry Back-Off Period + RW + Single + Mandatory + Integer + + + s + + + + SINR + R + Single + Mandatory + Integer + <7 to >12.5 + + + + + SRXLEV + R + Single + Mandatory + Integer + + + + + + + CE_LEVEL + R + Single + Mandatory + Integer + 0,1,2 + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10309.xml b/common/transport/lwm2m/src/main/resources/models/10309.xml new file mode 100644 index 0000000000..333580200e --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10309.xml @@ -0,0 +1,115 @@ + + + + + Shareparkinglot + + 10309 + urn:oma:lwm2m:x:10309 + 1.0 + 1.0 + Multiple + Optional + + + LockID + R + Single + Mandatory + Integer + + + + + + LockType + R + Single + Optional + String + + + + + + LightSwitchState + R + Multiple + Optional + Boolean + + + + + + RSSI + R + Multiple + Mandatory + Integer + -30..-120 + dBm + + + + BatteryCapacity + R + Multiple + Optional + Float + 0..100 + %EL + + + + DataUpTime + R + Multiple + Mandatory + Time + + + + + + Latitude + R + Multiple + Optional + String + + + + + + Longitude + R + Multiple + Optional + String + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10311.xml b/common/transport/lwm2m/src/main/resources/models/10311.xml new file mode 100644 index 0000000000..e622197164 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10311.xml @@ -0,0 +1,164 @@ + + + + + + + Solar Radiation + + This object is used to report solar irradiance (SI), i.e. power per unit area received from the Sun in the form of electromagnetic radiation, on a planar surface measured by a pyranometer or similar instrument. A pyranometer measures solar irradiance from the hemisphere above within a wavelength range 0.3 μm to 3 μm. For example, the application of solar radiation measurement can be meteorological networks and solar energy applications. + + 10311 + urn:oma:lwm2m:x:10311 + 1.0 + 1.0 + Multiple + Optional + + + Min Measured Value + R + Single + Optional + Float + + + + The minimum value measured by the sensor since it is ON or Reset, expressed in the unit defined by the "Sensor Units" resource if present. + + + + Max Measured Value + R + Single + Optional + Float + + + + The maximum value measured by the sensor since it is ON or Reset, expressed in the unit defined by the "Sensor Units" resource if present. + + + + Min Range Value + R + Single + Optional + Float + + + + The minimum value that can be measured by the sensor, expressed in the unit defined by the "Sensor Units" resource if present. + + + + Max Range Value + R + Single + Optional + Float + + + + The maximum value that can be measured by the sensor, expressed in the unit defined by the "Sensor Units" resource if present. + + + + Reset Min and Max Measured Values + E + Single + Optional + + + + + Reset the Min and Max Measured Values to current value. + + + + Timestamp + R + Single + Optional + Time + + + The timestamp of when the measurement was performed. + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor expressed in the unit defined by the "Sensor Units" resource if present. + + + Sensor Units + R + Single + Optional + String + + + + Measurement Units Definition. + + + + Application Type + RW + Single + Optional + String + + + + The application type of the sensor or actuator as a string, for instance "Air Pressure". + + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10313.xml b/common/transport/lwm2m/src/main/resources/models/10313.xml new file mode 100644 index 0000000000..4875e5d6b0 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10313.xml @@ -0,0 +1,253 @@ + + + + + + + Gas Readings + + 10313 + urn:oma:lwm2m:x:103131.0 + 1.0Multiple + Optional + + + Interval Period + R + Single + Mandatory + Integer + 1..864000 + s + + + + Interval Start Offset + R + Single + Optional + Integer + 0..86399 + s + + + + Interval UTC Offset + R + Single + Optional + String + + + + + + Interval Collection Start Time + R + Single + Mandatory + Time + + + + + + Oldest Recorded Interval + R + Single + Mandatory + Time + + + + + + Last Delivered Interval + RW + Single + Optional + Time + + + + + + Latest Recorded Interval + R + Single + Mandatory + Time + + + + + + Interval Delivery Midnight Aligned + RW + Single + Mandatory + Boolean + + + + + + Interval Historical Read + E + Single + Optional + + + + + + + Interval Historical Read Payload + R + Single + Optional + Opaque + + + + + + Interval Change Configuration + E + Single + Optional + + + + + + + Start + E + Single + Optional + + + + + + + Stop + E + Single + Optional + + + + + + + Status + R + Single + Optional + Integer + + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + Sensor Warm-up Time + RW + Single + Optional + Integer + 0..86400 + s + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10314.xml b/common/transport/lwm2m/src/main/resources/models/10314.xml new file mode 100644 index 0000000000..69f344ea34 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10314.xml @@ -0,0 +1,106 @@ + + + + + + + Particulates + + 10314 + urn:oma:lwm2m:x:10314 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + + + + Min Measured Value + R + Single + Optional + Float + + + + + + Max Measured Value + R + Single + Optional + Float + + + + + + Max Range Value + R + Single + Optional + Float + + + + + + Sensor Units + R + Single + Optional + String + + + + + + Application Type + RW + Single + Optional + String + + + The Application type of the device, for example “Particulate Sensor”. + + + Reset Min and Max Measured Values + E + Single + Optional + + + + + + + Measured Particle Size + R + Single + Mandatory + Float + + m + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10315.xml b/common/transport/lwm2m/src/main/resources/models/10315.xml new file mode 100644 index 0000000000..fcca456342 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10315.xml @@ -0,0 +1,129 @@ + + + + + + Robot + + 10315 + urn:oma:lwm2m:x:10315 + 1.0 + 1.0 + Single + Mandatory + + + Robot ID + R + Single + Mandatory + String + 0..255 + + + + + Robot Type + R + Single + Mandatory + String + 0..63 + + + + + Robot Serial Number + R + Single + Mandatory + String + 0..63 + + + + + Battery Level + R + Single + Mandatory + Integer + 0..100 + % + + + + Charging + R + Single + Mandatory + Boolean + + + + + + On time + RW + Single + Mandatory + Integer + + s + + + + Positioning + R + Single + Optional + Boolean + + + + + + Location + R + Single + Optional + Objlnk + + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10316.xml b/common/transport/lwm2m/src/main/resources/models/10316.xml new file mode 100644 index 0000000000..011055fde3 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10316.xml @@ -0,0 +1,233 @@ + + + + + + RCU + + 10316 + urn:oma:lwm2m:x:10316 + 1.0 + 1.0 + Single + Mandatory + + + RCU ID + R + Single + Mandatory + String + 0..127 + + + + + RCU Serial Number + R + Single + Mandatory + String + 0..63 + + + + + RCU Software Version + R + Single + Mandatory + String + 0..63 + + + + + RCU OS Version + R + Single + Mandatory + String + 0..127 + + + + + RCU CPU Info + R + Single + Mandatory + String + 64 + + + + + RCU RAM Info + R + Single + Mandatory + String + 64 + + + + + RCU ROM Size + R + Single + Mandatory + Integer + + GB + + + + RCU ROM Available Size + R + Single + Mandatory + Integer + + GB + + + + SD Storage + R + Single + Mandatory + Integer + + GB + + + + SD Available Storage + R + Single + Mandatory + Integer + + GB + + + + RCU GPS Location + R + Single + Optional + Objlnk + + + + + + Wi-Fi MAC + R + Single + Optional + String + 12 + + + + + Bluetooth MAC + R + Single + Optional + String + 12 + + + + + Camera Info + R + Single + Optional + String + 64 + + + + + + Battery Level + R + Single + Mandatory + Integer + 0..100 + /100 + + + + + On time + RW + Single + Mandatory + Integer + + s + + + + + Downloaded APP Packages + R + Multiple + Mandatory + String + + + + + + + RCU APPs + R + Multiple + Optional + Objlnk + + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10318.xml b/common/transport/lwm2m/src/main/resources/models/10318.xml new file mode 100644 index 0000000000..989db0de7e --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10318.xml @@ -0,0 +1,189 @@ + + + + + + RCU PM + + 10318 + urn:oma:lwm2m:x:10318 + 1.0 + 1.0 + Single + Mandatory + + + CPU Usage + R + Single + Mandatory + Integer + 0..100 + /100 + + + + Max CPU Usage + R + Single + Mandatory + Integer + 0..100 + /100 + + + + Memory Usage + R + Single + Mandatory + Integer + 0..100 + /100 + + + + Storage Usage + R + Single + Mandatory + Integer + 0..100 + /100 + + + + + Battery Level + R + Single + Mandatory + Integer + 0..100 + /100 + + + + Network Bandwidth + R + Single + Mandatory + Float + + Mbit/s + + + + Mobile Signal + R + Single + Mandatory + Integer + + + + + + GPS Signal + R + Single + Optional + Integer + + + + + + Wi-Fi Signal + R + Single + Mandatory + Integer + + + + + + UpLink Rate + R + Single + Mandatory + Float + + Mbit/s + + + + DownLink Rate + R + Single + Mandatory + Float + + Mbit/s + + + + Packet Loss Rate + R + Single + Mandatory + Integer + 0..100 + /100 + + + + Network Latency + R + Single + Mandatory + Integer + + ms + + + + + Battery Temperature + R + Single + Mandatory + Float + + Cel + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10319.xml b/common/transport/lwm2m/src/main/resources/models/10319.xml new file mode 100644 index 0000000000..b8ebcef6fb --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10319.xml @@ -0,0 +1,130 @@ + + + + + + RCU Control + + 10319 + urn:oma:lwm2m:x:10319 + 1.0 + 1.0 + Single + Mandatory + + + RCU Diagnostics Mode + R + Single + Optional + Boolean + + + + + + RCU Log Recording + R + Single + Optional + Boolean + + + + + + + RCU Shutdown + E + Single + Mandatory + + + + + + + RCU Restart + E + Single + Mandatory + + + + + + + RCU Deactivate + E + Single + Mandatory + + + + + + + RCU Reset + E + Single + Mandatory + + + + + + + RCU Diagnostics Mode Control + E + Single + Mandatory + + + + + + + RCU Log Recording Control + E + Single + Mandatory + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10320.xml b/common/transport/lwm2m/src/main/resources/models/10320.xml new file mode 100644 index 0000000000..2b46d7c920 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10320.xml @@ -0,0 +1,141 @@ + + + + + + CCU + + 10320 + urn:oma:lwm2m:x:10320 + 1.0 + 1.0 + Multiple + Optional + + + CCU ID + R + Single + Mandatory + String + + + + + + CCU FM Version + R + Single + Mandatory + String + + + + + + CCU SW Version + R + Single + Mandatory + String + + + + + + CCU Memory Size + R + Single + Mandatory + Integer + + GB + + + + CCU Storage + R + Single + Mandatory + Integer + + GB + + + + CCU Available Storage + R + Single + Mandatory + Integer + + GB + + + + + On time + RW + Single + Mandatory + Integer + + s + + + + + Downloaded APP Packages + R + Multiple + Optional + String + + + + + + CCU APPs + R + Multiple + Optional + Objlnk + + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10322.xml b/common/transport/lwm2m/src/main/resources/models/10322.xml new file mode 100644 index 0000000000..98822e0efe --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10322.xml @@ -0,0 +1,87 @@ + + + + + + CCU PM + + 10322 + urn:oma:lwm2m:x:10322 + 1.0 + 1.0 + Multiple + Optional + + + CPU Usage + R + Single + Optional + Integer + 0..100 + % + + + + Max CPU Usage + R + Single + Optional + Integer + 0..100 + % + + + + Memory Usage + R + Single + Optional + Integer + 0..100 + % + + + + Storage Usage + R + Single + Optional + Integer + 0..100 + % + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10323.xml b/common/transport/lwm2m/src/main/resources/models/10323.xml new file mode 100644 index 0000000000..dcbdaeb91d --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10323.xml @@ -0,0 +1,90 @@ + + + + + + CCU Control + + 10323 + urn:oma:lwm2m:x:10323 + 1.0 + 1.0 + Multiple + Optional + + + + CCU Restart + E + Single + Mandatory + + + + + + + CCU Reset + E + Single + Mandatory + + + + + + + CCU Self-checking + E + Single + Mandatory + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10324.xml b/common/transport/lwm2m/src/main/resources/models/10324.xml new file mode 100644 index 0000000000..e78bb099de --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10324.xml @@ -0,0 +1,77 @@ + + + + + + ECU + + 10324 + urn:oma:lwm2m:x:10324 + 1.0 + 1.0 + Multiple + Optional + + + ECU ID + R + Single + Mandatory + String + + + + + + ECU FM Version + R + Single + Mandatory + String + + + + + + On time + RW + Single + Mandatory + Integer + + s + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10326.xml b/common/transport/lwm2m/src/main/resources/models/10326.xml new file mode 100644 index 0000000000..353e549829 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10326.xml @@ -0,0 +1,722 @@ + + + + + + Robot PM + + 10326 + urn:oma:lwm2m:x:10326 + 1.0 + 1.0 + Single + Mandatory + + + Battery Level + R + Single + Mandatory + Integer + 0..100 + /100 + + + + + Battery Temperature + R + Single + Mandatory + Integer + + Cel + + + + Temperature + R + Single + Optional + Float + + Cel + + + + Humidity + R + Single + Optional + Integer + 0..100 + /100 + + + + PM2.5 + R + Single + Optional + Integer + + ug/m3 + + + + Smog + R + Single + Optional + Float + + ug/m3 + + + + CO + R + Single + Optional + Float + + ppm + + + + CO2 + R + Single + Optional + Float + + ppm + + + + PM10 + R + Single + Optional + Integer + + ug/m3 + + + + Speed + R + Single + Optional + Float + + m/h + + + + Water Used + R + Single + Optional + Integer + 0..100 + /100 + + + + Dust Box Used + R + Single + Optional + Integer + 0..100 + /100 + + + + Obstacle Distance + R + Single + Optional + Integer + + cm + + + + + Robot Temperate + R + Single + Optional + Float + + Cel + + + + Confidence Index + R + Single + Optional + Integer + 0..100 + /100 + + + + + Data Traffic Used + R + Single + Mandatory + Float + + Mbit/s + + + + Images Handled + R + Single + Optional + Integer + + + + + + HARI S-Voice Requests + R + Single + Optional + Integer + + + + + + HARI S-Vision Requests + R + Single + Optional + Integer + + + + + + HARI S-Motion Requests + R + Single + Optional + Integer + + + + + + HARI S-Map Requests + R + Single + Optional + Integer + + + + + + Successful HARI S-Voice Requests + R + Single + Optional + Integer + + + + + + Successful HARI S-Vision Requests + R + Single + Optional + Integer + + + + + + Successful HARI S-Motion Requests + R + Single + Optional + Integer + + + + + + Successful HARI S-Map Requests + R + Single + Optional + Integer + + + + + + Questions Answered + R + Single + Optional + Integer + + + + + + Unknown Questions + R + Single + Optional + Integer + + + + + + Mileage + R + Single + Optional + Integer + + m + + + + Cleaned Times + R + Single + Optional + Integer + + + + + + Cleaned Area + R + Single + Optional + Float + + m2 + + + + Cleaned Time + R + Single + Optional + Integer + + s + + + + ASR Recognized + R + Single + Optional + Integer + + B + + + + Incorrect ASR Recognitions + R + Single + Optional + Integer + + B + + + + Tried TTS Texts + R + Single + Optional + Integer + + B + + + + Successful TTS Texts + R + Single + Optional + Integer + + B + + + + ASR Recognized (CH) + R + Single + Optional + Integer + + B + + + + Tried TTS Texts (CH) + R + Single + Optional + Integer + + B + + + + Successful TTS Texts (CH) + R + Single + Optional + Integer + + B + + + + ASR Recognized (EN) + R + Single + Optional + Integer + + B + + + + Tried TTS Texts (EN) + R + Single + Optional + Integer + + B + + + + Successful TTS Texts (EN) + R + Single + Optional + Integer + + B + + + + ASR Recognized (ES) + R + Single + Optional + Integer + + B + + + + Tried TTS Texts (ES) + R + Single + Optional + Integer + + B + + + + Successful TTS Texts (ES) + R + Single + Optional + Integer + + B + + + + ASR Recognized (JA) + R + Single + Optional + Integer + + B + + + + Tried TTS Texts (JA) + R + Single + Optional + Integer + + B + + + + Successful TTS Texts (JA) + R + Single + Optional + Integer + + B + + + + ASR Recognized (SCCH) + R + Single + Optional + Integer + + B + + + + Tried TTS Texts (SCCH) + R + Single + Optional + Integer + + B + + + + Successful TTS Texts (SCCH) + R + Single + Optional + Integer + + B + + + + ASR Recognized (GDCH) + R + Single + Optional + Integer + + B + + + + Tried TTS Texts (GDCH) + R + Single + Optional + Integer + + B + + + + Successful TTS Texts (GDCH) + R + Single + Optional + Integer + + B + + + + ASR Recognized (TCH) + R + Single + Optional + Integer + + B + + + + Tried TTS Texts (TCH) + R + Single + Optional + Integer + + B + + + + Successful TTS Texts (TCH) + R + Single + Optional + Integer + + B + + + + + Objects Recognition Tries + R + Single + Optional + Integer + + + + + + Successful Object Recognition + R + Single + Optional + Integer + + + + + + Face Recognition Tries + R + Single + Optional + Integer + + + + + + Successful Face Recognitions + R + Single + Optional + Integer + + + + + + Vehicle Plate Recognition Tries + R + Single + Optional + Integer + + + + + + Successful Vehicle Plate Recognitions + R + Single + Optional + Integer + + + + + + Tasks Assigned + R + Single + Mandatory + Integer + + + + + + Successful Tasks Executed + R + Single + Mandatory + Integer + + + + + + Images Uploaded + R + Single + Optional + Integer + + + + + + Videos Uploaded + R + Single + Optional + Integer + + + + + + Images Matted + R + Single + Optional + Integer + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10327.xml b/common/transport/lwm2m/src/main/resources/models/10327.xml new file mode 100644 index 0000000000..5f0e232a22 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10327.xml @@ -0,0 +1,68 @@ + + + + + + Compressor + + 10327 + urn:oma:lwm2m:x:10327 + 1.0 + 1.0 + Multiple + Optional + + + Compressor Name + R + Single + Mandatory + String + + + + + + + Compressor Status + R + Single + Mandatory + Boolean + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10328.xml b/common/transport/lwm2m/src/main/resources/models/10328.xml new file mode 100644 index 0000000000..fdf39d5dc1 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10328.xml @@ -0,0 +1,80 @@ + + + + + + SCA PM + + 10328 + urn:oma:lwm2m:x:10328 + 1.0 + 1.0 + Multiple + Optional + + + SCA Name + R + Single + Mandatory + String + + + + + + + + + SCA Current + R + Single + Mandatory + Float + + A + + + + SCA Temperate + R + Single + Mandatory + Float + + Cel + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10329.xml b/common/transport/lwm2m/src/main/resources/models/10329.xml new file mode 100644 index 0000000000..7470bec6e1 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10329.xml @@ -0,0 +1,433 @@ + + + + + + Robot Control + + 10329 + urn:oma:lwm2m:x:10329 + 1.0 + 1.0 + Single + Mandatory + + + Collision Detection + R + Single + Optional + Boolean + + + + + + Drop Detection + R + Single + Optional + Boolean + + + + + + Automatic Navigation + R + Single + Optional + Boolean + + + + + + Robot Shutdown + E + Single + Mandatory + + + + + + + Robot Reboot + E + Single + Mandatory + + + + + + + Robot Reset + E + Single + Mandatory + + + + + + + Robot Wakeup + E + Single + Mandatory + + + + + + + Robot Sleep + E + Single + Mandatory + + + + + + + Robot Self-checking + E + Single + Mandatory + + + + + + + Emergency Braking + E + Single + Mandatory + + + + + + + Emergency Braking Release + E + Single + Mandatory + + + + + + + Action Execution + E + Single + Optional + + + + + + + Action List Upload + E + Single + Optional + + + + + + + Action List Download + E + Single + Optional + + + + + + + Group Dancing Program Control + E + Single + Optional + + + + + + + Navigation Map Upload + E + Single + Optional + + + + + + + Group Dancing Program Control + E + Single + Optional + + + + + + + Navigation Map Download + E + Single + Optional + + + + + + + Route list Execution + E + Single + Optional + + + + + + + Route list Upload + E + Single + Optional + + + + + + + Route list Download + E + Single + Optional + + + + + + + Automatic Navigation Control + E + Single + Optional + + + + + + + Manual Navigation + E + Single + Optional + + + + + + + Moving to Charging Station + E + Single + Optional + + + + + + + Moving to Specified location + E + Single + Optional + + + + + + + Low Frequency Patrol Broadcasting + E + Single + Optional + + + + + + + Task Start + E + Single + Optional + + + + + + + Task Stop + E + Single + Optional + + + + + + + Task Suspend + E + Single + Optional + + + + + + + Task Resume + E + Single + Optional + + + + + + + Video Upload + E + Single + Optional + + + + + + + Picture Upload + E + Single + Optional + + + + + + + Default Language Switching + E + Single + Optional + + + + + + + Intonation Change + E + Single + Optional + + + + + + + Intonation Change + E + Single + Optional + + + + + + + Speaking with Action + E + Single + Optional + + + + + + + Collision Detection Control + E + Single + Mandatory + + + + + + + Drop Detection Control + E + Single + Mandatory + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10330.xml b/common/transport/lwm2m/src/main/resources/models/10330.xml new file mode 100644 index 0000000000..75c5a2ecdd --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10330.xml @@ -0,0 +1,120 @@ + + + + + + Network Info + + 10330 + urn:oma:lwm2m:x:10330 + 1.0 + 1.0 + Single + Mandatory + + + IMEI + R + Single + Mandatory + String + 15 + + + + + IMSI + R + Single + Mandatory + String + 15 + + + + + Radio Connectivity + R + Single + Mandatory + Objlnk + + + + + + + + GPS Signal Status + R + Single + Optional + Integer + 1..4 + + + + + VBN Connection Status + R + Single + Mandatory + Integer + 0..1 + + + + + HARI Connection Status + R + Single + Mandatory + Integer + 0..1 + + + + + CCU Connection Status + R + Multiple + Optional + Integer + 0..1 + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10331.xml b/common/transport/lwm2m/src/main/resources/models/10331.xml new file mode 100644 index 0000000000..ca555cc0d9 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10331.xml @@ -0,0 +1,221 @@ + + + + + + Robot Service Info + + 10331 + urn:oma:lwm2m:x:10331 + 1.0 + 1.0 + Single + Mandatory + + + Current status + R + Single + Mandatory + String + 0..127 + + + + + Services Providing + R + Single + Optional + String + 0..127 + + + + + Advertising Contents + R + Single + Mandatory + String + + + + + + Current Language + R + Single + Optional + String + 0..127 + + + + + Volume + R + Single + Optional + String + 0..100 + /100 + + + + Moving Status + R + Single + Optional + Integer + 0..2 + + + + + Moving Speed + R + Single + Optional + Float + + m/h + + + + Location + R + Single + Optional + Objlnk + + + + + + + + Map List + R + Single + Optional + String + + + + + + Planned Route list + R + Single + Optional + String + + + + + + Current Route + R + Single + Optional + String + + + + + + Route to-do List + R + Single + Optional + String + + + + + + Synchronous Whistle + R + Single + Mandatory + Boolean + + + + + + Current Actions + R + Single + Optional + String + + + + + + ASR Type + R + Single + Optional + Integer + 0..2 + + + + + + TTS Vendor + R + Single + Optional + String + + + + + + TTS Speaker + R + Single + Optional + String + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10332.xml b/common/transport/lwm2m/src/main/resources/models/10332.xml new file mode 100644 index 0000000000..6bda413092 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10332.xml @@ -0,0 +1,69 @@ + + + + + + Robot Selfcheck Info + + 10332 + urn:oma:lwm2m:x:10332 + 1.0 + 1.0 + Multiple + Optional + + + Entity + R + Single + Mandatory + String + 4..63 + + + + + + + Status + R + Single + Mandatory + Integer + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10333.xml b/common/transport/lwm2m/src/main/resources/models/10333.xml new file mode 100644 index 0000000000..3a1f1f6dfa --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10333.xml @@ -0,0 +1,88 @@ + + + + + + PM Threshold + + 10333 + urn:oma:lwm2m:x:10333 + 1.0 + 1.0 + Single + Optional + + + Entity + RW + Multiple + Mandatory + String + 4..63 + + + + + Performance Type + RW + Multiple + Mandatory + String + + + + + + High Threshold + RW + Multiple + Mandatory + Float + + + + + + Low Threshold + RW + Multiple + Mandatory + Float + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10334.xml b/common/transport/lwm2m/src/main/resources/models/10334.xml new file mode 100644 index 0000000000..547fb7a0d5 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10334.xml @@ -0,0 +1,129 @@ + + + + + + Robot Alarm + + 10334 + urn:oma:lwm2m:x:10334 + 1.0 + 1.0 + Multiple + Optional + + + Entity + R + Single + Mandatory + String + 4..63 + + + + + Probable Cause + R + Single + Mandatory + Integer + 0..65535 + + + + + Specific Problem + R + Single + Mandatory + String + + + + + + Alarm Type + R + Single + Mandatory + Integer + 2..6 + + + + + Severity + R + Single + Mandatory + Integer + 1..5 + + + + + Report Time + R + Single + Mandatory + Time + + + + + + Sequence No + R + Single + Mandatory + Integer + 0..2^63-1 + + + + + Additional Info + R + Single + Optional + String + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10335.xml b/common/transport/lwm2m/src/main/resources/models/10335.xml new file mode 100644 index 0000000000..49640154e8 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10335.xml @@ -0,0 +1,97 @@ + + + + + + Event + + 10335 + urn:oma:lwm2m:x:10335 + 1.0 + 1.0 + Multiple + Optional + + + Entity + R + Single + Mandatory + String + 4..63 + + + + + Event Type + R + Single + Mandatory + Integer + 0..65535 + + + + + Time + R + Single + Mandatory + Time + + + + + + Sequence No + R + Single + Mandatory + Integer + 0..2^63-1 + + + + + Additional Info + R + Single + Optional + String + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10336.xml b/common/transport/lwm2m/src/main/resources/models/10336.xml new file mode 100644 index 0000000000..74fae1916a --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10336.xml @@ -0,0 +1,84 @@ + + + + + + MIC + + 10336 + urn:oma:lwm2m:x:10336 + 1.0 + 1.0 + Single + Optional + + + Host Device Unique ID + R + Single + Optional + String + + + + + + + + Host Device Manufacturer + R + Single + Optional + String + + + + + + + + Host Device Model Number + R + Single + Optional + String + + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10337.xml b/common/transport/lwm2m/src/main/resources/models/10337.xml new file mode 100644 index 0000000000..3220c8e3e0 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10337.xml @@ -0,0 +1,118 @@ + + + + + + SCA + + 10337 + urn:oma:lwm2m:x:10337 + 1.0 + 1.0 + Multiple + Optional + + + SCA Name + R + Single + Mandatory + String + + + + + + + + + + SCA Motion Status + R + Single + Optional + Integer + 0..2 + + + + + + SCA Motion Control + E + Single + Optional + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10338.xml b/common/transport/lwm2m/src/main/resources/models/10338.xml new file mode 100644 index 0000000000..48213fe176 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10338.xml @@ -0,0 +1,124 @@ + + + + + + Speaker + + 10338 + urn:oma:lwm2m:x:10338 + 1.0 + 1.0 + Single + Optional + + + Speaker status + R + Single + Mandatory + Boolean + + + + + + Voice Warning + R + Single + Mandatory + Boolean + + + + + + + Voice Control + E + Single + Mandatory + + + + + + + Voice Warning Control + E + Single + Mandatory + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10339.xml b/common/transport/lwm2m/src/main/resources/models/10339.xml new file mode 100644 index 0000000000..d93e5fd778 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10339.xml @@ -0,0 +1,114 @@ + + + + + + Tripod Head + + 10339 + urn:oma:lwm2m:x:10339 + 1.0 + 1.0 + Single + Optional + + + Host Device Unique ID + R + Single + Optional + String + + + + + + + + Host Device Manufacturer + R + Single + Optional + String + + + + + + + + Host Device Model Number + R + Single + Optional + String + + + + + + + + Tripod Direction Control + E + Single + Optional + + + + + + + Tripod Automatic Control + E + Single + Optional + + + + + + + Tripod Reset + E + Single + Optional + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10340.xml b/common/transport/lwm2m/src/main/resources/models/10340.xml new file mode 100644 index 0000000000..30123ba665 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10340.xml @@ -0,0 +1,218 @@ + + + + + + Camera + + 10340 + urn:oma:lwm2m:x:10340 + 1.0 + 1.0 + Multiple + Optional + + + Camera Name + R + Single + Mandatory + String + + + + + + + + Camera Status + R + Single + Mandatory + Boolean + + + + + + Connection Status + R + Single + Mandatory + Boolean + + + + + + Working Status + R + Single + Mandatory + Integer + 0..15 + + + + + Local Recording + R + Single + Mandatory + Boolean + + + + + + Image Matting + R + Single + Mandatory + Boolean + + + + + + Camera Snapshot + R + Single + Mandatory + Boolean + + + + + + Camera Recording + R + Single + Mandatory + Boolean + + + + + + + Camera Control + E + Single + Mandatory + + + + + + + Local Recording Control + E + Single + Mandatory + + + + + + + Image Matting Control + E + Single + Mandatory + + + + + + + Camera Snapshot Control + E + Single + Mandatory + + + + + + + Camera Recording Control + E + Single + Mandatory + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10341.xml b/common/transport/lwm2m/src/main/resources/models/10341.xml new file mode 100644 index 0000000000..ca00c3ab0c --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10341.xml @@ -0,0 +1,84 @@ + + + + + + GPS + + 10341 + urn:oma:lwm2m:x:10341 + 1.0 + 1.0 + Single + Optional + + + Host Device Unique ID + R + Single + Optional + String + + + + + + + + Host Device Manufacturer + R + Single + Optional + String + + + + + + + + Host Device Model Number + R + Single + Optional + String + + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10342.xml b/common/transport/lwm2m/src/main/resources/models/10342.xml new file mode 100644 index 0000000000..5a2c0d1982 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10342.xml @@ -0,0 +1,84 @@ + + + + + + IMU + + 10342 + urn:oma:lwm2m:x:10342 + 1.0 + 1.0 + Single + Optional + + + Host Device Unique ID + R + Single + Optional + String + + + + + + + + Host Device Manufacturer + R + Single + Optional + String + + + + + + + + Host Device Model Number + R + Single + Optional + String + + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10343.xml b/common/transport/lwm2m/src/main/resources/models/10343.xml new file mode 100644 index 0000000000..309c80884d --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10343.xml @@ -0,0 +1,96 @@ + + + + + + LiDAR + + 10343 + urn:oma:lwm2m:x:10343 + 1.0 + 1.0 + Multiple + Optional + + + LiDAR Name + R + Single + Mandatory + String + + + + + + + + Host Device Unique ID + R + Single + Optional + String + + + + + + + + Host Device Manufacturer + R + Single + Optional + String + + + + + + + + Host Device Model Number + R + Single + Optional + String + + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10344.xml b/common/transport/lwm2m/src/main/resources/models/10344.xml new file mode 100644 index 0000000000..9e3f80a491 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10344.xml @@ -0,0 +1,96 @@ + + + + + + Arm + + 10344 + urn:oma:lwm2m:x:10344 + 1.0 + 1.0 + Multiple + Optional + + + Arm Name + R + Single + Mandatory + String + + + + + + + + Host Device Unique ID + R + Single + Optional + String + + + + + + + + Host Device Manufacturer + R + Single + Optional + String + + + + + + + + Host Device Model Number + R + Single + Optional + String + + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10345.xml b/common/transport/lwm2m/src/main/resources/models/10345.xml new file mode 100644 index 0000000000..488ada316f --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10345.xml @@ -0,0 +1,96 @@ + + + + + + Leg + + 10345 + urn:oma:lwm2m:x:10345 + 1.0 + 1.0 + Multiple + Optional + + + Leg Name + R + Single + Mandatory + String + + + + + + + + Host Device Unique ID + R + Single + Optional + String + + + + + + + + Host Device Manufacturer + R + Single + Optional + String + + + + + + + + Host Device Model Number + R + Single + Optional + String + + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10346.xml b/common/transport/lwm2m/src/main/resources/models/10346.xml new file mode 100644 index 0000000000..f5b22f8763 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10346.xml @@ -0,0 +1,96 @@ + + + + + + Servomotor + + 10346 + urn:oma:lwm2m:x:10346 + 1.0 + 1.0 + Multiple + Optional + + + Servomotor Name + R + Single + Mandatory + String + + + + + + + + Host Device Unique ID + R + Single + Optional + String + + + + + + + + Host Device Manufacturer + R + Single + Optional + String + + + + + + + + Host Device Model Number + R + Single + Optional + String + + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10347.xml b/common/transport/lwm2m/src/main/resources/models/10347.xml new file mode 100644 index 0000000000..7c20b00a40 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10347.xml @@ -0,0 +1,154 @@ + + + + + + Screen + + 10347 + urn:oma:lwm2m:x:10347 + 1.0 + 1.0 + Single + Optional + + + Screen Status + R + Single + Mandatory + Boolean + + + + + + Startup Page + R + Single + Optional + String + + + The Startup Page of the screen. + + + Current Displaying Page or Current Screen Play List + R + Single + Optional + String + + + Current Displaying Page or Current Screen Play List. + + + + Screen Control + E + Single + Mandatory + + + + + + + Startup Page Set + E + Single + Mandatory + + + + + + + Screen Page Set + E + Single + Mandatory + + + + + + + Screen Play List Set + E + Single + Mandatory + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10348.xml b/common/transport/lwm2m/src/main/resources/models/10348.xml new file mode 100644 index 0000000000..3d8a2d460f --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10348.xml @@ -0,0 +1,96 @@ + + + + + + Wheel + + 10348 + urn:oma:lwm2m:x:10348 + 1.0 + 1.0 + Multiple + Optional + + + Wheel Name + R + Single + Mandatory + String + + + + + + + + Host Device Unique ID + R + Single + Optional + String + + + + + + + + Host Device Manufacturer + R + Single + Optional + String + + + + + + + + Host Device Model Number + R + Single + Optional + String + + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10349.xml b/common/transport/lwm2m/src/main/resources/models/10349.xml new file mode 100644 index 0000000000..8eb7d27ecf --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10349.xml @@ -0,0 +1,84 @@ + + + + + + Chassis + + 10349 + urn:oma:lwm2m:x:10349 + 1.0 + 1.0 + Single + Optional + + + Host Device Unique ID + R + Single + Optional + String + + + + + + + + Host Device Manufacturer + R + Single + Optional + String + + + + + + + + Host Device Model Number + R + Single + Optional + String + + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10350.xml b/common/transport/lwm2m/src/main/resources/models/10350.xml new file mode 100644 index 0000000000..64295e65bc --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10350.xml @@ -0,0 +1,116 @@ + + + + + + Light + + 10350 + urn:oma:lwm2m:x:10350 + 1.0 + 1.0 + Multiple + Optional + + + Light Name + R + Single + Mandatory + String + + + + + + + + Light Status + R + Single + Mandatory + Boolean + + + + + + + Light Control + E + Single + Mandatory + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10351.xml b/common/transport/lwm2m/src/main/resources/models/10351.xml new file mode 100644 index 0000000000..473b440b02 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10351.xml @@ -0,0 +1,79 @@ + + + + + + Door + + 10351 + urn:oma:lwm2m:x:10351 + 1.0 + 1.0 + Multiple + Optional + + + Door Name + R + Single + Mandatory + String + + + + + + + Door Status + R + Single + Mandatory + Boolean + + + + + + + Door Control + E + Single + Mandatory + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10352.xml b/common/transport/lwm2m/src/main/resources/models/10352.xml new file mode 100644 index 0000000000..da1dac5834 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10352.xml @@ -0,0 +1,114 @@ + + + + + + Thermal Imager + + 10352 + urn:oma:lwm2m:x:10352 + 1.0 + 1.0 + Single + Optional + + + + Highest Temperature + R + Single + Mandatory + Float + -100.0..100.0 + Cel + The Highest Temperature of the thermal imager. + + + Lowest Temperature + R + Single + Mandatory + Float + -100.0..100.0 + Cel + The Lowest Temperature of the thermal imager. + + + Average Temperature + R + Single + Mandatory + Float + -100.0..100.0 + Cel + The Average Temperature of the thermal imager. + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10353.xml b/common/transport/lwm2m/src/main/resources/models/10353.xml new file mode 100644 index 0000000000..0b6bb56cc4 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10353.xml @@ -0,0 +1,87 @@ + + + + + + Warning Light + + 10353 + urn:oma:lwm2m:x:10353 + 1.0 + 1.0 + Single + Optional + + + Light Status + R + Single + Mandatory + Boolean + + + + + + Light Warning + R + Single + Mandatory + Boolean + + + + + + Light Control + E + Single + Mandatory + + + + + + + Light Warning Control + E + Single + Mandatory + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10354.xml b/common/transport/lwm2m/src/main/resources/models/10354.xml new file mode 100644 index 0000000000..3459409720 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10354.xml @@ -0,0 +1,217 @@ + + + + + + APP + + 10354 + urn:oma:lwm2m:x:10354 + 1.0 + 1.0 + Multiple + Mandatory + + + APP Name + RW + Single + Mandatory + String + + + The name of the APP, human readable string. + + + APP Version + RW + Single + Mandatory + String + + + The version of the APP, human readable string. + + + APP Build No + RW + Single + Optional + String + + + The Build No of the APP, human readable string. + + + APP Patch No + RW + Single + Optional + String + + + The Patch No of the APP, human readable string. + + + Package URI + W + Single + Optional + String + 0-255 bytes + + + + + Vendor Name + RW + Single + Optional + String + + + The vendor of the package. + + + Installation Target + RW + Single + Mandatory + Objlnk + + + + + + APP Status + R + Single + Mandatory + Integer + 0..5 + + The Status of the APP, 0:Downloading, 1:Downloaded, 2:Installed, 3:Verified, 4:Activated, 5:Stopped. + + + APP Restart + E + Single + Mandatory + + + + + + + APP Start + E + Single + Mandatory + + + + + + + APP Stop + E + Single + Mandatory + + + + + + + APP Download + E + Single + Mandatory + + + + + + + APP Install + E + Single + Mandatory + + + + + + + APP Uninstall + E + Single + Mandatory + + + + + + + APP Activate + E + Single + Mandatory + + + + + + + APP Deactivate + E + Single + Mandatory + + + + + + + APP Verify + E + Single + Mandatory + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10355.xml b/common/transport/lwm2m/src/main/resources/models/10355.xml new file mode 100644 index 0000000000..fb38ee2767 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10355.xml @@ -0,0 +1,95 @@ + + + + + + General Info + + 10355 + urn:oma:lwm2m:x:10355 + 1.0 + 1.0 + Single + Optional + + + Robot General Info + R + Single + Mandatory + Objlnk + + + + + + + + RCU General Info + R + Single + Mandatory + Objlnk + + + + + + + + CCU General Info + R + Multiple + Optional + Objlnk + + + + + + + + ECU General Info + R + Multiple + Optional + Objlnk + + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10356.xml b/common/transport/lwm2m/src/main/resources/models/10356.xml new file mode 100644 index 0000000000..2e362ce052 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10356.xml @@ -0,0 +1,203 @@ + + + + + + Service Info + + 10356 + urn:oma:lwm2m:x:10356 + 1.0 + 1.0 + Single + Optional + + + Robot Service Info + R + Single + Mandatory + Objlnk + + + + + + + + SCA Info + R + Multiple + Optional + Objlnk + + + + + + + + Speaker Info + R + Single + Optional + Objlnk + + + + + + + + Camera Info + R + Multiple + Optional + Objlnk + + + + + + + + Screen Info + R + Single + Optional + Objlnk + + + + + + + + Light Info + R + Multiple + Optional + Objlnk + + + + + + + + Warning Light Info + R + Single + Optional + Objlnk + + + + + + + + Door Info + R + Multiple + Optional + Objlnk + + + + + + + + Thermal Imager Info + R + Single + Optional + Objlnk + + + + + + + + Compressor Info + R + Multiple + Optional + Objlnk + + + + + + + + Lock Info + R + Multiple + Optional + Objlnk + + + + + + + + Collision Sensor Info + R + Multiple + Optional + Objlnk + + + + + + + + Drop Sensor Info + R + Multiple + Optional + Objlnk + + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10357.xml b/common/transport/lwm2m/src/main/resources/models/10357.xml new file mode 100644 index 0000000000..9487b2813d --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10357.xml @@ -0,0 +1,95 @@ + + + + + + PM + + 10357 + urn:oma:lwm2m:x:10357 + 1.0 + 1.0 + Single + Optional + + + Robot PM + R + Single + Mandatory + Objlnk + + + + + + + + RCU PM + R + Single + Mandatory + Objlnk + + + + + + + + CCU PM + R + Multiple + Optional + Objlnk + + + + + + + + SCA PM + R + Multiple + Optional + Objlnk + + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10358.xml b/common/transport/lwm2m/src/main/resources/models/10358.xml new file mode 100644 index 0000000000..27a3684b22 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10358.xml @@ -0,0 +1,70 @@ + + + + + + Fan PM + + 10358 + urn:oma:lwm2m:x:10358 + 1.0 + 1.0 + Multiple + Optional + + + Fan Name + R + Single + Mandatory + String + + + + + + + + + Fan Speed + R + Single + Optional + Integer + + 1/min + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10359.xml b/common/transport/lwm2m/src/main/resources/models/10359.xml new file mode 100644 index 0000000000..2fc8af9677 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10359.xml @@ -0,0 +1,78 @@ + + + + + + Lock + + 10359 + urn:oma:lwm2m:x:10359 + 1.0 + 1.0 + Multiple + Optional + + + Lock Name + R + Single + Mandatory + String + + + + + + Lock Status + R + Single + Optional + Boolean + + + + + + + Lock Control + E + Single + Mandatory + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10360.xml b/common/transport/lwm2m/src/main/resources/models/10360.xml new file mode 100644 index 0000000000..935fea848c --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10360.xml @@ -0,0 +1,70 @@ + + + + + + Ultrasonic Sensor + + 10360 + urn:oma:lwm2m:x:10360 + 1.0 + 1.0 + Multiple + Optional + + + Name + R + Single + Mandatory + String + + + + + + + + + Status + R + Single + Mandatory + Integer + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10361.xml b/common/transport/lwm2m/src/main/resources/models/10361.xml new file mode 100644 index 0000000000..3525647afd --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10361.xml @@ -0,0 +1,92 @@ + + + + + + Collision Sensor + + 10361 + urn:oma:lwm2m:x:10361 + 1.0 + 1.0 + Multiple + Optional + + + Name + R + Single + Mandatory + String + + + + + + + + Status + R + Single + Mandatory + Integer + + + + + + + Collision Detection + R + Single + Optional + Boolean + + + + + + + Collision Detection Control + E + Single + Mandatory + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10362.xml b/common/transport/lwm2m/src/main/resources/models/10362.xml new file mode 100644 index 0000000000..8a928e4425 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10362.xml @@ -0,0 +1,91 @@ + + + + + + Drop Sensor + + 10362 + urn:oma:lwm2m:x:10362 + 1.0 + 1.0 + Multiple + Optional + + + Name + R + Single + Mandatory + String + + + + + + + + Status + R + Single + Mandatory + Integer + + + + + + Drop Detection + R + Single + Optional + Boolean + + + + + + + Drop Detection Control + E + Single + Mandatory + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10363.xml b/common/transport/lwm2m/src/main/resources/models/10363.xml new file mode 100644 index 0000000000..ca9d064f2f --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10363.xml @@ -0,0 +1,57 @@ + + + + + + Temperature Sensor + + 10363 + urn:oma:lwm2m:x:10363 + 1.0 + 1.0 + Single + Optional + + + Status + R + Single + Mandatory + Integer + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10364.xml b/common/transport/lwm2m/src/main/resources/models/10364.xml new file mode 100644 index 0000000000..3519665e62 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10364.xml @@ -0,0 +1,57 @@ + + + + + + Humidity Sensor + + 10364 + urn:oma:lwm2m:x:10364 + 1.0 + 1.0 + Single + Optional + + + Status + R + Single + Mandatory + Integer + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10365.xml b/common/transport/lwm2m/src/main/resources/models/10365.xml new file mode 100644 index 0000000000..792844271e --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10365.xml @@ -0,0 +1,57 @@ + + + + + + Gas-Dust Sensor + + 10365 + urn:oma:lwm2m:x:10365 + 1.0 + 1.0 + Single + Optional + + + Status + R + Single + Mandatory + Integer + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10366.xml b/common/transport/lwm2m/src/main/resources/models/10366.xml new file mode 100644 index 0000000000..44e94ae51d --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10366.xml @@ -0,0 +1,59 @@ + + + + + + Fan + + 10366 + urn:oma:lwm2m:x:10366 + 1.0 + 1.0 + Multiple + Optional + + + Fan Name + R + Single + Mandatory + String + + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10368.xml b/common/transport/lwm2m/src/main/resources/models/10368.xml new file mode 100644 index 0000000000..f063e010fe --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10368.xml @@ -0,0 +1,96 @@ + + + + + + SpringMotor + + 10368 + urn:oma:lwm2m:x:10368 + 1.0 + 1.0 + Multiple + Optional + + + SpringMotor Name + R + Single + Mandatory + String + + + + + + + + Host Device Unique ID + R + Single + Optional + String + + + + + + + + Host Device Manufacturer + R + Single + Optional + String + + + + + + + + Host Device Model Number + R + Single + Optional + String + + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/10369.xml b/common/transport/lwm2m/src/main/resources/models/10369.xml new file mode 100644 index 0000000000..68c345beaf --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/10369.xml @@ -0,0 +1,84 @@ + + + + + + MCU + + 10369 + urn:oma:lwm2m:x:10369 + 1.0 + 1.0 + Single + Optional + + + Host Device Unique ID + R + Single + Optional + String + + + + + + + + Host Device Manufacturer + R + Single + Optional + String + + + + + + + + Host Device Model Number + R + Single + Optional + String + + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/2048.xml b/common/transport/lwm2m/src/main/resources/models/2048.xml new file mode 100644 index 0000000000..0bc99cffd1 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/2048.xml @@ -0,0 +1,90 @@ + + + + + + + CmdhPolicy + + 2048 + urn:oma:lwm2m:ext:20481.0 + 1.0Multiple + Optional + + Name + RW + Single + Mandatory + String + + + + + DefaultRule + RW + Single + Mandatory + Objlnk + + + + + LimiRules + RW + Multiple + Mandatory + Objlnk + + + + + NetworkAccessECRules + RW + Multiple + Mandatory + Objlnk + + + + + BufferRules + RW + Multiple + Mandatory + Objlnk + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/2049.xml b/common/transport/lwm2m/src/main/resources/models/2049.xml new file mode 100644 index 0000000000..7509b22160 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/2049.xml @@ -0,0 +1,59 @@ + + + + + + + ActiveCmdhPolicy + + 2049 + urn:oma:lwm2m:ext:20491.0 + 1.0Single + Optional + + ActiveLink + RW + Single + Mandatory + Objlnk + + + + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/2050.xml b/common/transport/lwm2m/src/main/resources/models/2050.xml new file mode 100644 index 0000000000..da27a90de0 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/2050.xml @@ -0,0 +1,64 @@ + + + + + + + CmdhDefaults + + 2050 + urn:oma:lwm2m:ext:20501.0 + 1.0Multiple + Optional + + DefaultEcRules + RW + Multiple + Mandatory + Objlnk + + + + + + DefaultEcParamRules + RW + Multiple + Mandatory + Objlnk + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/2051.xml b/common/transport/lwm2m/src/main/resources/models/2051.xml new file mode 100644 index 0000000000..f3904e8a2c --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/2051.xml @@ -0,0 +1,99 @@ + + + + + + + CmdhDefEcValues + + 2051 + urn:oma:lwm2m:ext:20511.0 + 1.0Multiple + Optional + + Order + RW + Single + Mandatory + Integer + + + + + DefEcValue + RW + Single + Mandatory + String + + + + + RequestOrigin + RW + Multiple + Mandatory + String + + + + + RequestContext + RW + Single + Optional + String + + + + + RequestContextNotification + RW + Single + Optional + Boolean + + + + + RequestCharacteristics + RW + Single + Optional + String + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/2052.xml b/common/transport/lwm2m/src/main/resources/models/2052.xml new file mode 100644 index 0000000000..abaae1b54e --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/2052.xml @@ -0,0 +1,111 @@ + + + + + + + CmdhEcDefParamValues + + 2052 + urn:oma:lwm2m:ext:20521.0 + 1.0Multiple + Optional + + ApplicableEventCategory + RW + Multiple + Mandatory + Integer + + + + + DefaultRequestExpTime + RW + Single + Mandatory + Integer + + ms + + + + + + + + + DefaultResultExpTime + RW + Single + Mandatory + Integer + + ms + + + + DefaultOpExecTime + RW + Single + Mandatory + Integer + + ms + + + DefaultRespPersistence + RW + Single + Mandatory + Integer + + ms + + + DefaultDelAggregation + RW + Single + Mandatory + Integer + + ms + + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/2053.xml b/common/transport/lwm2m/src/main/resources/models/2053.xml new file mode 100644 index 0000000000..0b119c70fc --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/2053.xml @@ -0,0 +1,165 @@ + + + + + + + CmdhLimits + + 2053 + urn:oma:lwm2m:ext:20531.0 + 1.0Multiple + Optional + + Order + RW + Single + Mandatory + Integer + + + + + RequestOrigin + RW + Multiple + Mandatory + String + + + + + + + + + + + RequestContext + RW + Single + Optional + String + + + + + + RequestContextNotificatio + RW + Single + Optional + Boolean + + + + + RequestCharacteristics + RW + Single + Optional + String + + + + + LimitsEventCategory + RW + Multiple + Mandatory + Integer + + + + + LimitsRequestExpTime + RW + Multiple + Mandatory + Integer + 2 Instances + ms + + + LimitsResultExpTime + RW + Multiple + Mandatory + Integer + 2 Instances + ms + + + LimitsOptExpTime + RW + Multiple + Mandatory + Integer + 2 Instances + ms + + + LimitsRespPersistence + RW + Multiple + Mandatory + Integer + 2 Instances + ms + + + LimitsDelAggregation + RW + Multiple + Mandatory + String + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/2054.xml b/common/transport/lwm2m/src/main/resources/models/2054.xml new file mode 100644 index 0000000000..3935fb7253 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/2054.xml @@ -0,0 +1,69 @@ + + + + + + + CmdhNetworkAccessRules + + 2054 + urn:oma:lwm2m:ext:20541.0 + 1.0Multiple + Optional + + ApplicableEventCategories + RW + Multiple + Mandatory + Integer + + + + + NetworkAccessRule + RW + Multiple + Optional + Objlnk + + + + + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/2055.xml b/common/transport/lwm2m/src/main/resources/models/2055.xml new file mode 100644 index 0000000000..cbd0dc5796 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/2055.xml @@ -0,0 +1,100 @@ + + + + + + + CmdhNwAccessRule + + 2055 + urn:oma:lwm2m:ext:20551.0 + 1.0Multiple + Optional + + TargetNetwork + RW + Multiple + Mandatory + String + + + + + SpreadingWaitTime + RW + Single + Mandatory + Integer + + ms + + + MinReqVolume + RW + Single + Mandatory + Integer + + B + + + BackOffParameters + RW + Single + Mandatory + Objlnk + + + + + OtherConditions + RW + Single + Mandatory + String + + + + + AllowedSchedule + RW + Multiple + Mandatory + String + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/2056.xml b/common/transport/lwm2m/src/main/resources/models/2056.xml new file mode 100644 index 0000000000..ddd50e269a --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/2056.xml @@ -0,0 +1,77 @@ + + + + + + + CmdhBuffer + + 2056 + urn:oma:lwm2m:ext:20561.0 + 1.0Multiple + Optional + + ApplicableEventCategory + RW + Multiple + Mandatory + Integer + + + + + MaxBufferSize + RW + Single + Mandatory + Integer + + B + + + StoragePriority + RW + Single + Mandatory + Integer + 1..10 + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/2057.xml b/common/transport/lwm2m/src/main/resources/models/2057.xml new file mode 100644 index 0000000000..68d4bcd135 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/2057.xml @@ -0,0 +1,92 @@ + + + + + + + CmdhBackOffParametersSet + + 2057 + urn:oma:lwm2m:ext:2057 + 1.0 + 1.0 + Multiple + Optional + + NetworkAction + RW + Single + Optional + Integer + 1..5 + + + + InitialBackoffTime + RW + Single + Mandatory + Integer + + ms + + + AdditionalBackoffTime + RW + Single + Mandatory + Integer + + ms + + + MaximumBackoffTime + RW + Single + Mandatory + Integer + + ms + + + OptionalRandomBackoffTime + RW + Multiple + Optional + Integer + + ms + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/31024.xml b/common/transport/lwm2m/src/main/resources/models/31024.xml new file mode 100644 index 0000000000..85ba52a79d --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/31024.xml @@ -0,0 +1,51 @@ + + + + Test + A Wakaama object for testing purpose. + + 31024 + urn:oma:lwm2m:x:31024 + Multiple + Optional + + + test + RW + Single + Mandatory + Integer + 0-255 + + + + exec + E + Single + Mandatory + + + + dec + RW + Single + Mandatory + Float + + + + + + sig + RW + Single + Optional + Integer + + + 16-bit signed integer + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3200.xml b/common/transport/lwm2m/src/main/resources/models/3200.xml new file mode 100644 index 0000000000..5a0dce0378 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3200.xml @@ -0,0 +1,129 @@ + + + + + + + + Digital Input + Generic digital input for non-specific sensors + 3200 + urn:oma:lwm2m:ext:3200 + 1.0 + 1.0 + Multiple + Optional + + + Digital Input State + R + Single + Mandatory + Boolean + + + The current state of a digital input. + + + Digital Input Counter + R + Single + Optional + Integer + + + The cumulative value of active state detected. + + + Digital Input Polarity + RW + Single + Optional + Boolean + + + The polarity of the digital input as a Boolean (False = Normal, True = Reversed). + + + Digital Input Debounce + RW + Single + Optional + Integer + + ms + The debounce period in ms. + + + Digital Input Edge Selection + RW + Single + Optional + Integer + 1..3 + + The edge selection as an integer (1 = Falling edge, 2 = Rising edge, 3 = Both Rising and Falling edge). + + + Digital Input Counter Reset + E + Single + Optional + + + + Reset the Counter value. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string, for instance, "Air Pressure" + + + Sensor Type + R + Single + Optional + String + + + The type of the sensor (for instance PIR type) + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3201.xml b/common/transport/lwm2m/src/main/resources/models/3201.xml new file mode 100644 index 0000000000..0920d9b030 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3201.xml @@ -0,0 +1,78 @@ + + + + + + + Digital Output + Generic digital output for non-specific actuators + 3201 + urn:oma:lwm2m:ext:3201 + 1.0 + 1.0 + Multiple + Optional + + + Digital Output State + RW + Single + Mandatory + Boolean + + + The current state of a digital output. + + + Digital Output Polarity + RW + Single + Optional + Boolean + + + The polarity of the digital output as a Boolean (False = Normal, True = Reversed). + + + Application Type + RW + Single + Optional + String + + + The application type of the output as a string, for instance, "LED" + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3202.xml b/common/transport/lwm2m/src/main/resources/models/3202.xml new file mode 100644 index 0000000000..413ba0103b --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3202.xml @@ -0,0 +1,128 @@ + + + + + + + Analog Input + Generic analog input for non-specific sensors + 3202 + urn:oma:lwm2m:ext:3202 + 1.0 + 1.0 + Multiple + Optional + + + Analog Input Current Value + R + Single + Mandatory + Float + + + The current value of the analog input. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string, for instance, "Air Pressure" + + + Sensor Type + R + Single + Optional + String + + + The type of the sensor, for instance PIR type + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3203.xml b/common/transport/lwm2m/src/main/resources/models/3203.xml new file mode 100644 index 0000000000..e807aca00a --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3203.xml @@ -0,0 +1,88 @@ + + + + + + + Analog Output + This IPSO object is a generic object that can be used with any kind of analog output interface. + 3203 + urn:oma:lwm2m:ext:3203 + 1.0 + 1.0 + Multiple + Optional + + + Analog Output Current Value + RW + Single + Mandatory + Float + 0..1 + + The current state of the analogue output. + + + Application Type + RW + Single + Optional + String + + + If present, the application type of the actuator as a string, for instance, "Valve" + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be set for the output + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be set for the output + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3300.xml b/common/transport/lwm2m/src/main/resources/models/3300.xml new file mode 100644 index 0000000000..58cf4f67cb --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3300.xml @@ -0,0 +1,138 @@ + + + + + + + Generic Sensor + This IPSO object allows the description of a generic sensor. It is based on the description of a value and a unit according to the SenML specification. Thus, any type of value defined within this specification can be reported using this object. This object may be used as a generic object if a dedicated one does not exist. + 3300 + urn:oma:lwm2m:ext:3300 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Application Type + RW + Single + Optional + String + + + If present, the application type of the sensor as a string, for instance, "CO2" + + + Sensor Type + R + Single + Optional + String + + + The type of the sensor (for instance PIR type) + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3301.xml b/common/transport/lwm2m/src/main/resources/models/3301.xml new file mode 100644 index 0000000000..7dfb81d230 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3301.xml @@ -0,0 +1,118 @@ + + + + + + + Illuminance + Illuminance sensor, example units = lx + 3301 + urn:oma:lwm2m:ext:3301 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + The current value of the luminosity sensor. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3302.xml b/common/transport/lwm2m/src/main/resources/models/3302.xml new file mode 100644 index 0000000000..0223d2f772 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3302.xml @@ -0,0 +1,108 @@ + + + + + + + Presence + Presence sensor with digital sensing, optional delay parameters + 3302 + urn:oma:lwm2m:ext:3302 + 1.0 + 1.0 + Multiple + Optional + + + Digital Input State + R + Single + Mandatory + Boolean + + + The current state of the presence sensor + + + Digital Input Counter + R + Single + Optional + Integer + + + The cumulative value of active state detected. + + + Digital Input Counter Reset + E + Single + Optional + + + + Reset the Counter value + + + Sensor Type + R + Single + Optional + String + + + The type of the sensor (for instance PIR type) + + + Busy to Clear delay + RW + Single + Optional + Integer + + ms + Delay from the detection state to the clear state in ms + + + Clear to Busy delay + RW + Single + Optional + Integer + + ms + Delay from the clear state to the busy state in ms + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3303.xml b/common/transport/lwm2m/src/main/resources/models/3303.xml new file mode 100644 index 0000000000..b638c932a8 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3303.xml @@ -0,0 +1,118 @@ + + + + + + + Temperature + This IPSO object should be used with a temperature sensor to report a temperature measurement. It also provides resources for minimum/maximum measured values and the minimum/maximum range that can be measured by the temperature sensor. An example measurement unit is degrees Celsius. + 3303 + urn:oma:lwm2m:ext:3303 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3304.xml b/common/transport/lwm2m/src/main/resources/models/3304.xml new file mode 100644 index 0000000000..61d65c998b --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3304.xml @@ -0,0 +1,118 @@ + + + + + + + Humidity + This IPSO object should be used with a humidity sensor to report a humidity measurement. It also provides resources for minimum/maximum measured values and the minimum/maximum range that can be measured by the humidity sensor. An example measurement unit is relative humidity as a percentage. + 3304 + urn:oma:lwm2m:ext:3304 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3305.xml b/common/transport/lwm2m/src/main/resources/models/3305.xml new file mode 100644 index 0000000000..cd50b18907 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3305.xml @@ -0,0 +1,228 @@ + + + + + + + Power Measurement + This IPSO object should be used over a power measurement sensor to report a remote power measurement. It also provides resources for minimum/maximum measured values and the minimum/maximum range for both active and reactive power. It also provides resources for cumulative energy, calibration, and the power factor. + 3305 + urn:oma:lwm2m:ext:3305 + 1.0 + 1.0 + Multiple + Optional + + + Instantaneous active power + R + Single + Mandatory + Float + + W + The current active power + + + Min Measured active power + R + Single + Optional + Float + + W + The minimum active power measured by the sensor since it is ON + + + Max Measured active power + R + Single + Optional + Float + + W + The maximum active power measured by the sensor since it is ON + + + Min Range active power + R + Single + Optional + Float + + W + The minimum active power that can be measured by the sensor + + + Max Range active power + R + Single + Optional + Float + + W + The maximum active power that can be measured by the sensor + + + Cumulative active power + R + Single + Optional + Float + + Wh + The cumulative active power since the last cumulative energy reset or device start + + + Active Power Calibration + W + Single + Optional + Float + + W + Request an active power calibration by writing the value of a calibrated load. + + + Instantaneous reactive power + R + Single + Optional + Float + + var + The current reactive power + + + Min Measured reactive power + R + Single + Optional + Float + + var + The minimum reactive power measured by the sensor since it is ON + + + Max Measured reactive power + R + Single + Optional + Float + + var + The maximum reactive power measured by the sensor since it is ON + + + Min Range reactive power + R + Single + Optional + Float + + var + The minimum active power that can be measured by the sensor + + + Max Range reactive power + R + Single + Optional + Float + + var + The maximum reactive power that can be measured by the sensor + + + Cumulative reactive power + R + Single + Optional + Float + + varh + The cumulative reactive power since the last cumulative energy reset or device start + + + Reactive Power Calibration + W + Single + Optional + Float + + var + Request a reactive power calibration by writing the value of a calibrated load. + + + Power factor + R + Single + Optional + Float + + + If applicable, the power factor of the current consumption. + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Reset Cumulative energy + E + Single + Optional + + + + Reset both cumulative active/reactive power + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3306.xml b/common/transport/lwm2m/src/main/resources/models/3306.xml new file mode 100644 index 0000000000..6e76808d96 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3306.xml @@ -0,0 +1,98 @@ + + + + + + + Actuation + This IPSO object is dedicated to remote actuation such as ON/OFF action or dimming. A multi-state output can also be described as a string. This is useful to send pilot wire orders for instance. It also provides a resource to reflect the time that the device has been switched on. + 3306 + urn:oma:lwm2m:ext:3306 + 1.0 + 1.0 + Multiple + Optional + + + On/Off + RW + Single + Mandatory + Boolean + + + On/off control. Boolean value where True is On and False is Off. + + + Dimmer + RW + Single + Optional + Integer + 0..100 + /100 + This resource represents a light dimmer setting, which has an Integer value between 0 and 100 as a percentage. + + + On time + RW + Single + Optional + Integer + + s + The time in seconds that the device has been on. Writing a value of 0 resets the counter. + + + Muti-state Output + RW + Single + Optional + String + + + A string describing a state for multiple level output such as Pilot Wire + + + Application Type + RW + Single + Optional + String + + + The Application type of the device, for example "Motion Closure". + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3308.xml b/common/transport/lwm2m/src/main/resources/models/3308.xml new file mode 100644 index 0000000000..865df6235f --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3308.xml @@ -0,0 +1,88 @@ + + + + + + + Set Point + This IPSO object should be used to set a desired value to a controller, such as a thermostat. A special resource is added to set the colour of an object. + 3308 + urn:oma:lwm2m:ext:3308 + 1.0 + 1.0 + Multiple + Optional + + + Set Point Value + RW + Single + Mandatory + Float + + + The setpoint value. + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Colour + RW + Single + Optional + String + + + A string representing a value in some color space + + + Application Type + RW + Single + Optional + String + + + The Application type of the device, for example "Motion Closure". + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3310.xml b/common/transport/lwm2m/src/main/resources/models/3310.xml new file mode 100644 index 0000000000..75e381f488 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3310.xml @@ -0,0 +1,108 @@ + + + + + + + Load Control + This Object is used for demand-response load control and other load control in automation application (not limited to power). + 3310 + urn:oma:lwm2m:ext:3310 + 1.0 + 1.0 + Multiple + Optional + + + Event Identifier + RW + Single + Mandatory + String + + + The event identifier as a string. + + + Start Time + RW + Single + Mandatory + Time + + + Time when the event started. + + + Duration In Min + RW + Single + Mandatory + Integer + + min + The duration of the event in minutes. + + + Criticality Level + RW + Single + Optional + Integer + 0..3 + + The criticality of the event. The device receiving the event will react in an appropriate fashion for the device. + + + Avg Load AdjPct + RW + Single + Optional + Integer + 0..100 + /100 + Defines the maximum energy usage of the receiving device, as a percentage of the device's normal maximum energy usage. + + + Duty Cycle + RW + Single + Optional + Integer + 0..100 + /100 + Defines the duty cycle for the load control event, i.e, what percentage of time the receiving device is allowed to be on. + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3311.xml b/common/transport/lwm2m/src/main/resources/models/3311.xml new file mode 100644 index 0000000000..2e7b3977b6 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3311.xml @@ -0,0 +1,127 @@ + + + + + + Light Control + This Object is used to control a light source, such as a LED or other light. It allows a light to be turned on or off and its dimmer setting to be control as a % between 0 and 100. An optional colour setting enables a string to be used to indicate the desired colour. + 3311 + urn:oma:lwm2m:ext:3311 + 1.0 + 1.0 + Multiple + Optional + + + On/Off + RW + Single + Mandatory + Boolean + + + On/off control. Boolean value where True is On and False is Off. + + + Dimmer + RW + Single + Optional + Integer + 0..100 + /100 + This resource represents a light dimmer setting, which has an Integer value between 0 and 100 as a percentage. + + + On time + RW + Single + Optional + Integer + + s + The time in seconds that the light has been on. Writing a value of 0 resets the counter. + + + Cumulative active power + R + Single + Optional + Float + + Wh + The total power in Wh that the light has used. + + + Power factor + R + Single + Optional + Float + + + The power factor of the light. + + + Colour + RW + Single + Optional + String + + + A string representing a value in some color space + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string, for instance, "Air Pressure" + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3312.xml b/common/transport/lwm2m/src/main/resources/models/3312.xml new file mode 100644 index 0000000000..fca6d7926a --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3312.xml @@ -0,0 +1,107 @@ + + + + + + Power Control + This Object is used to control a power source, such as a Smart Plug. It allows a power relay to be turned on or off and its dimmer setting to be control as a % between 0 and 100. + 3312 + urn:oma:lwm2m:ext:3312 + 1.0 + 1.0 + Multiple + Optional + + + On/Off + RW + Single + Mandatory + Boolean + + + On/off control. Boolean value where True is On and False is Off. + + + Dimmer + RW + Single + Optional + Integer + 0..100 + /100 + This resource represents a power dimmer setting, which has an Integer value between 0 and 100 as a percentage. + + + On time + RW + Single + Optional + Integer + + s + The time in seconds that the power relay has been on. Writing a value of 0 resets the counter. + + + Cumulative active power + R + Single + Optional + Float + + Wh + The total power in Wh that has been used by the load. + + + Power factor + R + Single + Optional + Float + + + The power factor of the load. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string, for instance, "Air Pressure" + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3313.xml b/common/transport/lwm2m/src/main/resources/models/3313.xml new file mode 100644 index 0000000000..df8dd8b573 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3313.xml @@ -0,0 +1,107 @@ + + + + + + Accelerometer + This IPSO object can be used to represent a 1-3 axis accelerometer. + 3313 + urn:oma:lwm2m:ext:3313 + 1.0 + 1.0 + Multiple + Optional + + + X Value + R + Single + Mandatory + Float + + + The measured value along the X axis. + + + Y Value + R + Single + Optional + Float + + + The measured value along the Y axis. + + + Z Value + R + Single + Optional + Float + + + The measured value along the Z axis. + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3314.xml b/common/transport/lwm2m/src/main/resources/models/3314.xml new file mode 100644 index 0000000000..0dcd28e625 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3314.xml @@ -0,0 +1,97 @@ + + + + + + Magnetometer + This IPSO object can be used to represent a 1-3 axis magnetometer with optional compass direction. + 3314 + urn:oma:lwm2m:ext:3314 + 1.0 + 1.0 + Multiple + Optional + + + X Value + R + Single + Mandatory + Float + + + The measured value along the X axis. + + + Y Value + R + Single + Optional + Float + + + The measured value along the Y axis. + + + Z Value + R + Single + Optional + Float + + + The measured value along the Z axis. + + + Compass Direction + R + Single + Optional + Float + 0..360 + deg + The measured compass direction. + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3315.xml b/common/transport/lwm2m/src/main/resources/models/3315.xml new file mode 100644 index 0000000000..1e010d3186 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3315.xml @@ -0,0 +1,118 @@ + + + + + + + Barometer + This IPSO object should be used with an air pressure sensor to report a barometer measurement. It also provides resources for minimum/maximum measured values and the minimum/maximum range that can be measured by the barometer sensor. An example measurement unit is pascals. + 3315 + urn:oma:lwm2m:ext:3315 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3316.xml b/common/transport/lwm2m/src/main/resources/models/3316.xml new file mode 100644 index 0000000000..63a769bea2 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3316.xml @@ -0,0 +1,139 @@ + + + + + + + Voltage + This IPSO object should be used with voltmeter sensor to report measured voltage between two points. It also provides resources for minimum and maximum measured values, as well as the minimum and maximum range that can be measured by the sensor. An example measurement unit is volts. + + 3316 + urn:oma:lwm2m:ext:3316 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3317.xml b/common/transport/lwm2m/src/main/resources/models/3317.xml new file mode 100644 index 0000000000..f3c0303438 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3317.xml @@ -0,0 +1,139 @@ + + + + + + + Current + This IPSO object should be used with an ammeter to report measured electric current in amperes. It also provides resources for minimum and maximum measured values, as well as the minimum and maximum range that can be measured by the sensor. An example measurement unit is ampere. + + 3317 + urn:oma:lwm2m:ext:3317 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3318.xml b/common/transport/lwm2m/src/main/resources/models/3318.xml new file mode 100644 index 0000000000..e7b69cd460 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3318.xml @@ -0,0 +1,139 @@ + + + + + + + Frequency + This IPSO object should be used to report frequency measurements. It also provides resources for minimum and maximum measured values, as well as the minimum and maximum range that can be measured by the sensor. An example measurement unit is hertz. + + 3318 + urn:oma:lwm2m:ext:3318 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3319.xml b/common/transport/lwm2m/src/main/resources/models/3319.xml new file mode 100644 index 0000000000..19d074a6eb --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3319.xml @@ -0,0 +1,139 @@ + + + + + + + Depth + This IPSO object should be used to report depth measurements. It can, for example, be used to describe a generic rain gauge that measures the accumulated rainfall in millimetres (mm). + + 3319 + urn:oma:lwm2m:ext:3319 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3320.xml b/common/transport/lwm2m/src/main/resources/models/3320.xml new file mode 100644 index 0000000000..d43fe7f315 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3320.xml @@ -0,0 +1,139 @@ + + + + + + + Percentage + This IPSO object should can be used to report measurements relative to a 0-100% scale. For example it could be used to measure the level of a liquid in a vessel or container in units of %. + + 3320 + urn:oma:lwm2m:ext:3320 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3321.xml b/common/transport/lwm2m/src/main/resources/models/3321.xml new file mode 100644 index 0000000000..0e57a8917b --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3321.xml @@ -0,0 +1,139 @@ + + + + + + + Altitude + This IPSO object should be used with an altitude sensor to report altitude above sea level in meters. Note that Altitude can be calculated from the measured pressure given the local sea level pressure. It also provides resources for minimum and maximum measured values, as well as the minimum and maximum range that can be measured by the sensor. An example measurement unit is meters. + + 3321 + urn:oma:lwm2m:ext:3321 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3322.xml b/common/transport/lwm2m/src/main/resources/models/3322.xml new file mode 100644 index 0000000000..c1eb6557c7 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3322.xml @@ -0,0 +1,139 @@ + + + + + + + Load + This IPSO object should be used with a load sensor (as in a scale) to report the applied weight or force. It also provides resources for minimum and maximum measured values, as well as the minimum and maximum range that can be measured by the sensor. An example measurement unit is kilograms. + + 3322 + urn:oma:lwm2m:ext:3322 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3323.xml b/common/transport/lwm2m/src/main/resources/models/3323.xml new file mode 100644 index 0000000000..16c409931d --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3323.xml @@ -0,0 +1,139 @@ + + + + + + + Pressure + This IPSO object should be used to report pressure measurements. It also provides resources for minimum and maximum measured values, as well as the minimum and maximum range that can be measured by the sensor. An example measurement unit is pascals. + + 3323 + urn:oma:lwm2m:ext:3323 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3324.xml b/common/transport/lwm2m/src/main/resources/models/3324.xml new file mode 100644 index 0000000000..e23c76b5dc --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3324.xml @@ -0,0 +1,139 @@ + + + + + + + Loudness + This IPSO object should be used to report loudness or noise level measurements. It also provides resources for minimum and maximum measured values, as well as the minimum and maximum range that can be measured by the sensor. An example measurement unit is decibels. + + 3324 + urn:oma:lwm2m:ext:3324 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3325.xml b/common/transport/lwm2m/src/main/resources/models/3325.xml new file mode 100644 index 0000000000..2defd9af1e --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3325.xml @@ -0,0 +1,139 @@ + + + + + + + Concentration + This IPSO object should be used to the particle concentration measurement of a medium. It also provides resources for minimum and maximum measured values, as well as the minimum and maximum range that can be measured by the sensor. An example measurement unit is parts per million. + + 3325 + urn:oma:lwm2m:ext:3325 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3326.xml b/common/transport/lwm2m/src/main/resources/models/3326.xml new file mode 100644 index 0000000000..7d3f940649 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3326.xml @@ -0,0 +1,139 @@ + + + + + + + Acidity + This IPSO object should be used to report an acidity measurement of a liquid. It also provides resources for minimum and maximum measured values, as well as the minimum and maximum range that can be measured by the sensor. An example measurement unit is pH. + + 3326 + urn:oma:lwm2m:ext:3326 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3327.xml b/common/transport/lwm2m/src/main/resources/models/3327.xml new file mode 100644 index 0000000000..32498aba39 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3327.xml @@ -0,0 +1,139 @@ + + + + + + + Conductivity + This IPSO object should be used to report a measurement of the electric conductivity of a medium or sample. It also provides resources for minimum and maximum measured values, as well as the minimum and maximum range that can be measured by the sensor. An example measurement unit is Siemens. + + 3327 + urn:oma:lwm2m:ext:3327 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3328.xml b/common/transport/lwm2m/src/main/resources/models/3328.xml new file mode 100644 index 0000000000..4c920b05ae --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3328.xml @@ -0,0 +1,139 @@ + + + + + + + Power + This IPSO object should be used to report power measurements. It also provides resources for minimum and maximum measured values, as well as the minimum and maximum range that can be measured by the sensor. An example measurement unit is Watts. This object may be used for either real power or apparent power measurements. + + 3328 + urn:oma:lwm2m:ext:3328 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3329.xml b/common/transport/lwm2m/src/main/resources/models/3329.xml new file mode 100644 index 0000000000..ba96e5bf9d --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3329.xml @@ -0,0 +1,139 @@ + + + + + + + Power Factor + This IPSO object should be used to report a measurement or calculation of the power factor of a reactive electrical load. Power Factor is normally the ratio of non-reactive power to total power. This object also provides resources for minimum and maximum measured values, as well as the minimum and maximum range that can be measured by the sensor. + + 3329 + urn:oma:lwm2m:ext:3329 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3330.xml b/common/transport/lwm2m/src/main/resources/models/3330.xml new file mode 100644 index 0000000000..5583596aa8 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3330.xml @@ -0,0 +1,139 @@ + + + + + + + Distance + This IPSO object should be used to report a distance measurement. It also provides resources for minimum and maximum measured values, as well as the minimum and maximum range that can be measured by the sensor. An example measurement unit is Meters. + + 3330 + urn:oma:lwm2m:ext:3330 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3331.xml b/common/transport/lwm2m/src/main/resources/models/3331.xml new file mode 100644 index 0000000000..8933e75c69 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3331.xml @@ -0,0 +1,89 @@ + + + + + + + Energy + This IPSO object should be used to report energy consumption (Cumulative Power) of an electrical load. An example measurement unit is Watt Hours. + + 3331 + urn:oma:lwm2m:ext:3331 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor. + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Reset Cumulative energy + E + Single + Optional + + + + Reset both cumulative active/reactive power. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3332.xml b/common/transport/lwm2m/src/main/resources/models/3332.xml new file mode 100644 index 0000000000..e39fb6f182 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3332.xml @@ -0,0 +1,99 @@ + + + + + + + Direction + This IPSO object is used to report the direction indicated by a compass, wind vane, or other directional indicator. The units of measure is plane angle degrees. + + 3332 + urn:oma:lwm2m:ext:3332 + 1.0 + 1.0 + Multiple + Optional + + + Compass Direction + R + Single + Mandatory + Float + 0..360 + deg + The measured compass direction. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset. + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset. + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3333.xml b/common/transport/lwm2m/src/main/resources/models/3333.xml new file mode 100644 index 0000000000..7282e2670a --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3333.xml @@ -0,0 +1,78 @@ + + + + + + Time + This IPSO object is used to report the current time in seconds since January 1, 1970 UTC. There is also a fractional time counter that has a range of less than one second. + + 3333 + urn:oma:lwm2m:ext:3333 + 1.0 + 1.0 + Multiple + Optional + + + Current Time + RW + Single + Mandatory + Time + + + Unix Time. A signed integer representing the number of seconds since Jan 1st, 1970 in the UTC time zone. + + + Fractional Time + RW + Single + Optional + Float + 0..1 + s + Fractional part of the time when sub-second precision is used (e.g., 0.23 for 230 ms). + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3334.xml b/common/transport/lwm2m/src/main/resources/models/3334.xml new file mode 100644 index 0000000000..8fb30e0164 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3334.xml @@ -0,0 +1,189 @@ + + + + + + + Gyrometer + This IPSO Object is used to report the current reading of a gyrometer sensor in 3 axes. It provides tracking of the minimum and maximum angular rate in all 3 axes. An example unit of measure is radians per second. + + 3334 + urn:oma:lwm2m:ext:3334 + 1.0 + 1.0 + Multiple + Optional + + + X Value + R + Single + Mandatory + Float + + + The measured value along the X axis. + + + Y Value + R + Single + Optional + Float + + + The measured value along the Y axis. + + + Z Value + R + Single + Optional + Float + + + The measured value along the Z axis. + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min X Value + R + Single + Optional + Float + + + The minimum measured value along the X axis + + + Max X Value + R + Single + Optional + Float + + + The maximum measured value along the X axis + + + Min Y Value + R + Single + Optional + Float + + + The minimum measured value along the Y axis + + + Max Y Value + R + Single + Optional + Float + + + The maximum measured value along the Y axis + + + Min Z Value + R + Single + Optional + Float + + + The minimum measured value along the Z axis + + + Max Z Value + R + Single + Optional + Float + + + The maximum measured value along the Z axis + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value. + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3335.xml b/common/transport/lwm2m/src/main/resources/models/3335.xml new file mode 100644 index 0000000000..8d48093231 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3335.xml @@ -0,0 +1,79 @@ + + + + + + + Colour + This IPSO object should be used to report the measured value of a colour sensor in some colour space described by the units resource. + + 3335 + urn:oma:lwm2m:ext:3335 + 1.0 + 1.0 + Multiple + Optional + + + Colour + RW + Single + Mandatory + String + + + A string representing a value in some colour space. + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3336.xml b/common/transport/lwm2m/src/main/resources/models/3336.xml new file mode 100644 index 0000000000..30aba24708 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3336.xml @@ -0,0 +1,119 @@ + + + + + + + Location + This IPSO object represents GPS coordinates. This object is compatible with the LWM2M management object for location, but uses reusable resources. + + 3336 + urn:oma:lwm2m:ext:3336 + 1.0 + 1.0 + Multiple + Optional + + + Latitude + R + Single + Mandatory + String + + + The decimal notation of latitude, e.g. -43.5723 (World Geodetic System 1984). + + + Longitude + R + Single + Mandatory + String + + + The decimal notation of longitude, e.g. 153.21760 (World Geodetic System 1984). + + + Uncertainty + R + Single + Optional + String + + + The accuracy of the position in meters. + + + Compass Direction + R + Single + Optional + Float + 0..360 + deg + The measured compass direction. + + + Velocity + R + Single + Optional + Opaque + + + The velocity of the device as defined in 3GPP 23.032 GAD specification. This set of values may not be available if the device is static. + + + Timestamp + R + Single + Optional + Time + + + The timestamp of when the measurement was performed. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3337.xml b/common/transport/lwm2m/src/main/resources/models/3337.xml new file mode 100644 index 0000000000..54f3d19d54 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3337.xml @@ -0,0 +1,139 @@ + + + + + + + Positioner + This IPSO object should be used with a generic position actuator with range from 0 to 100%. This object optionally allows setting the transition time for an operation that changes the position of the actuator, and for reading the remaining time of the currently active transition. + + 3337 + urn:oma:lwm2m:ext:3337 + 1.0 + 1.0 + Multiple + Optional + + + Current Position + RW + Single + Mandatory + Float + 0..100 + /100 + Current position or desired position of a positioner actuator. + + + Transition Time + RW + Single + Optional + Float + + s + The time expected to move the actuator to the new position. + + + Remaining Time + R + Single + Optional + Float + + s + The time remaining in an operation. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value set on the actuator since power ON or reset. + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value set on the actuator since power ON or reset. + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value. + + + Min Limit + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor. + + + Max Limit + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3338.xml b/common/transport/lwm2m/src/main/resources/models/3338.xml new file mode 100644 index 0000000000..1437a62c65 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3338.xml @@ -0,0 +1,99 @@ + + + + + + + Buzzer + This IPSO object should be used to actuate an audible alarm such as a buzzer, beeper, or vibration alarm. There is a dimmer control for setting the relative loudness of the alarm, and an optional duration control to limit the length of time the alarm sounds when turned on. Each time "true" is written to the On/Off resource, the alarm will sound again for the configured duration. If no duration is programmed or the setting is "false", writing a "true" to the On/Off resource will result in the alarm sounding continuously until a "false" is written to the On/Off resource. + + 3338 + urn:oma:lwm2m:ext:3338 + 1.0 + 1.0 + Multiple + Optional + + + On/Off + RW + Single + Mandatory + Boolean + + + On/off control. Boolean value where True is On and False is Off. + + + Level + RW + Single + Optional + Float + 0..100 + /100 + Audio volume control, float value between 0 and 100 as a percentage. + + + Delay Duration + RW + Single + Optional + Float + + s + The duration of the time delay. + + + Minimum Off-time + RW + Single + Mandatory + Float + + s + The off time when On/Off control remains on. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3339.xml b/common/transport/lwm2m/src/main/resources/models/3339.xml new file mode 100644 index 0000000000..edd11709e8 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3339.xml @@ -0,0 +1,98 @@ + + + + + + + Audio Clip + This IPSO object should be used for a speaker that plays a pre-recorded audio clip or an audio output that is sent elsewhere. For example, an elevator which announces the floor of the building. A resource is provided to store the clip, a dimmer resource controls the relative sound level of the playback, and a duration resource limits the maximum playback time. After the duration time is reached, any remaining samples in the clip are ignored, and the clip player will be ready to play another clip. + 3339 + urn:oma:lwm2m:ext:3339 + 1.0 + 1.0 + Multiple + Optional + + + Clip + RW + Single + Mandatory + Opaque + + + Audio clip that is playable (e.g., a short audio recording indicating the floor in an elevator). + + + Trigger + E + Single + Optional + + + + Trigger initiating actuation. + + + Level + RW + Single + Optional + Float + 0..100 + /100 + Audio volume control, float value between 0 and 100 as a percentage. + + + Duration + RW + Single + Optional + Float + + s + The duration of the sound once trigger. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3340.xml b/common/transport/lwm2m/src/main/resources/models/3340.xml new file mode 100644 index 0000000000..16585224fa --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3340.xml @@ -0,0 +1,159 @@ + + + + + + + Timer + This IPSO object is used to time events and actions, using patterns common to industrial timers. A write to the trigger resource or On/Off input state change starts the timing operation, and the timer remaining time shows zero when the operation is complete. The patterns supported are One-Shot (mode 1), On-Time or Interval (mode 2), Time delay on pick-up or TDPU (mode 3), and Time Delay on Drop-Out or TDDO (mode 4). Mode 0 disables the timer, so the output follows the input with no delay. A counter is provided to count occurrences of the timer output changing from 0 to 1. Writing a value of zero resets the counter. The Digital Input State resource reports the state of the timer output. + + 3340 + urn:oma:lwm2m:ext:3340 + 1.0 + 1.0 + Multiple + Optional + + + Delay Duration + RW + Single + Mandatory + Float + + s + The duration of the time delay. + + + Remaining Time + R + Single + Optional + Float + + s + The time remaining in an operation. + + + Minimum Off-time + RW + Single + Optional + Float + + s + The duration of the rearm delay (i.e. the delay from the end of one cycle until the beginning of the next, the inhibit time). + + + Trigger + E + Single + Optional + + + + Trigger initiating actuation. + + + On/Off + RW + Single + Optional + Boolean + + + On/off control. Boolean value where True is On and False is Off. + + + Digital Input Counter + R + Single + Optional + Integer + + + The number of times the input. + + + Cumulative Time + RW + Single + Optional + Float + + s + The total time in seconds that the timer input is true. Writing a 0 resets the time. + + + Digital State + R + Single + Optional + Boolean + + + The current state of the timer output. + + + Counter + RW + Single + Optional + Integer + + + Counts the number of times the timer output transitions from 0 to 1. + + + Timer Mode + RW + Single + Optional + Integer + 0..4 + + Type of timer pattern used by the patterns. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3341.xml b/common/transport/lwm2m/src/main/resources/models/3341.xml new file mode 100644 index 0000000000..55865d0f32 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3341.xml @@ -0,0 +1,139 @@ + + + + + + + Addressable Text Display + This IPSO object is used to send text to a text-only or text mode graphics display. Writing a string of text to the text resource causes it to be displayed at the selected X and Y locations on the display. If X or Y are set to a value greater than the size of the display, the position "wraps around" to the modulus of the setting and the display size. Likewise, if the text string overflows the display size, the text "wraps around" and displays on the next line down or, if the last line has been written, wraps around to the top of the display. Brightness and Contrast controls are provided to allow control of various display types including STN and DSTN type LCD character displays. Writing an empty payload to the Clear Display resource causes the display to be erased. + + 3341 + urn:oma:lwm2m:ext:3341 + 1.0 + 1.0 + Multiple + Optional + + + Text + RW + Single + Mandatory + String + + + A string of text. + + + X Coordinate + RW + Single + Optional + Integer + + + X Coordinate. + + + Y Coordinate + RW + Single + Optional + Integer + + + Y Coordinate. + + + Max X Coordinate + R + Single + Optional + Integer + + + The highest X coordinate the display supports before wrapping to the next line. + + + Max Y Coordinate + R + Single + Optional + Integer + + + The highest Y coordinate the display supports before wrapping to the next line. + + + Clear Display + E + Single + Optional + + + + Command to clear the display. + + + Level + RW + Single + Optional + Float + 0..100 + /100 + Brightness control, integer value between 0 and 100 as a percentage. + + + Contrast + RW + Single + Optional + Float + 0..100 + /100 + Proportional control, integer value between 0 and 100 as a percentage. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3342.xml b/common/transport/lwm2m/src/main/resources/models/3342.xml new file mode 100644 index 0000000000..b88ebab9d4 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3342.xml @@ -0,0 +1,98 @@ + + + + + + + On/Off switch + This IPSO object should be used with an On/Off switch to report the state of the switch. + 3342 + urn:oma:lwm2m:ext:3342 + 1.0 + 1.0 + Multiple + Optional + + + Digital Input State + R + Single + Mandatory + Boolean + + + The current state of a digital input. + + + Digital Input Counter + R + Single + Optional + Integer + + + The number of times the input transitions from 0 to 1. + + + On time + RW + Single + Optional + Integer + + s + The time in seconds since the On command was sent. Writing a value of 0 resets the counter. + + + Off Time + RW + Single + Optional + Integer + + s + The time in seconds since the Off command was sent. Writing a value of 0 resets the counter. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3343.xml b/common/transport/lwm2m/src/main/resources/models/3343.xml new file mode 100644 index 0000000000..63b77c3e91 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3343.xml @@ -0,0 +1,89 @@ + + + + + + + Dimmer + This IPSO object should be used with a dimmer or level control to report the state of the control. + + 3343 + urn:oma:lwm2m:ext:3343 + 1.0 + 1.0 + Multiple + Optional + + + Level + RW + Single + Mandatory + Float + 0..100 + /100 + Proportional control, integer value between 0 and 100 as a percentage. + + + On time + RW + Single + Optional + Integer + + s + The time in seconds that the dimmer has been on (Dimmer value has to be > 0). Writing a value of 0 resets the counter. + + + Off Time + RW + Single + Optional + Integer + + s + The time in seconds that the dimmer has been off (dimmer value less or equal to 0) Writing a value of 0 resets the counter. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3344.xml b/common/transport/lwm2m/src/main/resources/models/3344.xml new file mode 100644 index 0000000000..2dd8648a19 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3344.xml @@ -0,0 +1,99 @@ + + + + + + + Up/Down Control + This IPSO object is used to report the state of an up/down control element like a pair of push buttons or a rotary encoder. Counters for increase and decrease operations are provided for counting pulses from a quadrature encoder. + + 3344 + urn:oma:lwm2m:ext:3344 + 1.0 + 1.0 + Multiple + Optional + + + Increase Input State + R + Single + Mandatory + Boolean + + + Indicates an increase control action. + + + Decrease Input State + R + Single + Mandatory + Boolean + + + Indicates a decrease control action. + + + Up Counter + RW + Single + Optional + Integer + + + Counts the number of times the increase control has been operated. Writing a 0 resets the counter. + + + Down Counter + RW + Single + Optional + Integer + + + Counts the times the decrease control has been operated. Writing a 0 resets the counter. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3345.xml b/common/transport/lwm2m/src/main/resources/models/3345.xml new file mode 100644 index 0000000000..a5355c94ca --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3345.xml @@ -0,0 +1,109 @@ + + + + + + + Multiple Axis Joystick + This IPSO object can be used to report the position of a shuttle or joystick control. A digital input is provided to report the state of an associated push button. + + 3345 + urn:oma:lwm2m:ext:3345 + 1.0 + 1.0 + Multiple + Optional + + + Digital Input State + R + Single + Optional + Boolean + + + The current state of a digital input. + + + Digital Input Counter + R + Single + Optional + Integer + + + The number of times the input transitions from 0 to 1. + + + X Value + R + Single + Optional + Float + + + The measured value along the X axis. + + + Y Value + R + Single + Optional + Float + + + The measured value along the Y axis. + + + Z Value + R + Single + Optional + Float + + + The measured value along the Z axis. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3346.xml b/common/transport/lwm2m/src/main/resources/models/3346.xml new file mode 100644 index 0000000000..8c68054c39 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3346.xml @@ -0,0 +1,139 @@ + + + + + + + Rate + This object type should be used to report a rate measurement, for example the speed of a vehicle, or the rotational speed of a drive shaft. It also provides resources for minimum and maximum measured values, as well as the minimum and maximum range that can be measured by the sensor. An example measurement unit is meters per second (m/s). + + 3346 + urn:oma:lwm2m:ext:3346 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3347.xml b/common/transport/lwm2m/src/main/resources/models/3347.xml new file mode 100644 index 0000000000..f86a986f0a --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3347.xml @@ -0,0 +1,79 @@ + + + + + + + Push button + This IPSO object is used to report the state of a momentary action push button control and to count the number of times the control has been operated since the last observation. + + 3347 + urn:oma:lwm2m:ext:3347 + 1.0 + 1.0 + Multiple + Optional + + + Digital Input State + R + Single + Mandatory + Boolean + + + The current state of a digital input. + + + Digital Input Counter + R + Single + Optional + Integer + + + The number of times the input transitions from 0 to 1. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3348.xml b/common/transport/lwm2m/src/main/resources/models/3348.xml new file mode 100644 index 0000000000..a2de51f6af --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3348.xml @@ -0,0 +1,69 @@ + + + + + + + Multi-state Selector + This IPSO object is used to represent the state of a Multi-state selector switch with a number of fixed positions. + + 3348 + urn:oma:lwm2m:ext:3348 + 1.0 + 1.0 + Multiple + Optional + + + Multi-state Input + R + Single + Mandatory + Integer + + + The current state of a Multi-state input or selector. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3349.xml b/common/transport/lwm2m/src/main/resources/models/3349.xml new file mode 100644 index 0000000000..9a77820703 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3349.xml @@ -0,0 +1,88 @@ + + + + + + + Bitmap + Summarize several digital inputs to one value by mapping each bit to a digital input. + 3349 + urn:oma:lwm2m:ext:3349 + 1.0 + 1.0 + Multiple + Optional + + + Bitmap Input + R + Single + Mandatory + Integer + + + Integer in which each of the bits are associated with specific digital input value. Represented as a binary signed integer in network byte order, and in two's complement representation. Using values in range 0-127 is recommended to avoid ambiguities with byte order and negative values. + + + Bitmap Input Reset + E + Single + Optional + + + + Reset the Bitmap Input value. + + + Element Description + RW + Multiple + Optional + String + + + The description of each bit as a string. First instance describes the least significant bit, second instance the second least significant bit. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3350.xml b/common/transport/lwm2m/src/main/resources/models/3350.xml new file mode 100644 index 0000000000..dc1313cd83 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3350.xml @@ -0,0 +1,88 @@ + + + + + + + Stopwatch + An ascending timer that counts how long time has passed since the timer was started after reset. + 3350 + urn:oma:lwm2m:ext:3350 + 1.0 + 1.0 + Multiple + Optional + + + Cumulative Time + RW + Single + Mandatory + Float + + s + The total time in seconds that the stopwatch has been on. Writing a 0 resets the time. + + + On/Off + RW + Single + Optional + Boolean + + + On/off control. Boolean value where True is On and False is Off. + + + Digital Input Counter + R + Single + Optional + Integer + + + The number of times the input transitions from off to on. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3351.xml b/common/transport/lwm2m/src/main/resources/models/3351.xml new file mode 100644 index 0000000000..9219a765df --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3351.xml @@ -0,0 +1,131 @@ + + + powerupLog + + 3351 + urn:oma:lwm2m:ext:3351 + 1.0 + 1.0 + Single + Optional + + deviceName + R + Single + Mandatory + String + + + + + toolVersion + R + Single + Mandatory + String + + + + + IMEI + R + Single + Mandatory + String + + + + + IMSI + R + Single + Mandatory + String + + + + + MSISDN + R + Single + Mandatory + String + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3352.xml b/common/transport/lwm2m/src/main/resources/models/3352.xml new file mode 100644 index 0000000000..260daa033a --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3352.xml @@ -0,0 +1,124 @@ + + + plmnSearchEvent + + 3352 + urn:oma:lwm2m:ext:3352 + 1.0 + 1.0 + Multiple + Optional + + timeScanStart + R + Single + Mandatory + Integer + + + + + plmnID + R + Single + Mandatory + Integer + + + + + BandIndicator + R + Single + Mandatory + Integer + + + + + dlEarfcn + R + Single + Mandatory + Integer + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3353.xml b/common/transport/lwm2m/src/main/resources/models/3353.xml new file mode 100644 index 0000000000..95b87e40b7 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3353.xml @@ -0,0 +1,123 @@ + + + scellID + + 3353 + urn:oma:lwm2m:ext:3353 + 1.0 + 1.0 + Single + Optional + + plmnID + R + Single + Mandatory + Integer + + + + + BandIndicator + R + Single + Mandatory + Integer + + + + + TrackingAreaCode + R + Single + Mandatory + Integer + + + + + CellID + R + Single + Mandatory + Integer + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3354.xml b/common/transport/lwm2m/src/main/resources/models/3354.xml new file mode 100644 index 0000000000..065a330d38 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3354.xml @@ -0,0 +1,134 @@ + + + cellReselectionEvent + + 3354 + urn:oma:lwm2m:ext:3354 + 1.0 + 1.0 + Single + Optional + + timeReselectionStart + R + Single + Mandatory + Integer + + + + + dlEarfcn + R + Single + Mandatory + Integer + + + + + CellID + R + Single + Mandatory + Integer + + + + + failureType + R + Single + Mandatory + Integer + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3355.xml b/common/transport/lwm2m/src/main/resources/models/3355.xml new file mode 100644 index 0000000000..627d67b68e --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3355.xml @@ -0,0 +1,156 @@ + + + handoverEvent + + 3355 + urn:oma:lwm2m:ext:3355 + 1.0 + 1.0 + Single + Optional + + timeHandoverStart + R + Single + Mandatory + Integer + + + + + dlEarfcn + R + Single + Mandatory + Integer + + + + + CellID + R + Single + Mandatory + Integer + + + + + handoverResult + R + Single + Mandatory + Integer + + + + + + TargetEarfcn + R + Single + Mandatory + Integer + + + + + TargetPhysicalCellID + R + Single + Mandatory + Integer + + + + + targetCellRsrp + R + Single + Mandatory + Integer + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3356.xml b/common/transport/lwm2m/src/main/resources/models/3356.xml new file mode 100644 index 0000000000..95c7fc7835 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3356.xml @@ -0,0 +1,120 @@ + + + radioLinkFailureEvent + + 3356 + urn:oma:lwm2m:ext:3356 + 1.0 + 1.0 + Single + Optional + + timeRLF + R + Single + Mandatory + Integer + + + + + rlfCause + R + Single + Mandatory + Integer + + + + + + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3357.xml b/common/transport/lwm2m/src/main/resources/models/3357.xml new file mode 100644 index 0000000000..935b7c4ba7 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3357.xml @@ -0,0 +1,131 @@ + + + rrcStateChangeEvent + + 3357 + urn:oma:lwm2m:ext:3357 + 1.0 + 1.0 + Single + Optional + + rrcState + R + Single + Mandatory + Integer + + + + + rrcStateChangeCause + R + Single + Mandatory + Integer + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3358.xml b/common/transport/lwm2m/src/main/resources/models/3358.xml new file mode 100644 index 0000000000..2784d6a990 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3358.xml @@ -0,0 +1,106 @@ + + + rrcTimerExpiryEvent + + 3358 + urn:oma:lwm2m:ext:3358 + 1.0 + 1.0 + Single + Optional + + RrcTimerExpiryEvent + R + Single + Mandatory + Integer + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3359.xml b/common/transport/lwm2m/src/main/resources/models/3359.xml new file mode 100644 index 0000000000..630e52ce8f --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3359.xml @@ -0,0 +1,105 @@ + + + cellBlacklistEvent + + 3359 + urn:oma:lwm2m:ext:3359 + 1.0 + 1.0 + Single + Optional + + dlEarfcn + R + Single + Mandatory + Integer + + + + + CellID + R + Single + Mandatory + Integer + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3360.xml b/common/transport/lwm2m/src/main/resources/models/3360.xml new file mode 100644 index 0000000000..12b2302854 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3360.xml @@ -0,0 +1,128 @@ + + + esmContextInfo + + 3360 + urn:oma:lwm2m:ext:3360 + 1.0 + 1.0 + Single + Optional + + contextType + R + Single + Mandatory + Integer + + + + + bearerState + R + Single + Mandatory + Integer + + + + + radioBearerId + R + Single + Mandatory + Integer + + + + + qci + R + Single + Mandatory + Integer + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3361.xml b/common/transport/lwm2m/src/main/resources/models/3361.xml new file mode 100644 index 0000000000..3d354bffac --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3361.xml @@ -0,0 +1,130 @@ + + + emmStateValue + + 3361 + urn:oma:lwm2m:ext:3361 + 1.0 + 1.0 + Single + Optional + + EmmState + R + Single + Mandatory + Integer + + + + + emmSubstate + R + Single + Mandatory + Integer + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3362.xml b/common/transport/lwm2m/src/main/resources/models/3362.xml new file mode 100644 index 0000000000..3cb73eb79a --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3362.xml @@ -0,0 +1,97 @@ + + + nasEmmTimerExpiryEvent + + 3362 + urn:oma:lwm2m:ext:3362 + 1.0 + 1.0 + Single + Optional + + NasEmmTimerExpiryEvent + R + Single + Mandatory + Integer + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3363.xml b/common/transport/lwm2m/src/main/resources/models/3363.xml new file mode 100644 index 0000000000..3b44b91f26 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3363.xml @@ -0,0 +1,100 @@ + + + nasEsmExpiryEvent + + 3363 + urn:oma:lwm2m:ext:3363 + 1.0 + 1.0 + Single + Optional + + NasEsmExpiryEvent + R + Single + Mandatory + Integer + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3364.xml b/common/transport/lwm2m/src/main/resources/models/3364.xml new file mode 100644 index 0000000000..0a042d12d2 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3364.xml @@ -0,0 +1,97 @@ + + + emmFailureCauseEvent + + 3364 + urn:oma:lwm2m:ext:3364 + 1.0 + 1.0 + Single + Optional + + EMMCause + R + Single + Mandatory + Integer + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3365.xml b/common/transport/lwm2m/src/main/resources/models/3365.xml new file mode 100644 index 0000000000..99f1b3885c --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3365.xml @@ -0,0 +1,123 @@ + + + rachLatency_delay + + 3365 + urn:oma:lwm2m:ext:3365 + 1.0 + 1.0 + Single + Optional + + sysFrameNumber + R + Single + Mandatory + Integer + + + + + subFrameNumber + R + Single + Mandatory + Integer + + + + + rachLatencyVal + R + Single + Mandatory + Integer + + + + + delay + R + Single + Mandatory + Integer + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3366.xml b/common/transport/lwm2m/src/main/resources/models/3366.xml new file mode 100644 index 0000000000..5498af2a3d --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3366.xml @@ -0,0 +1,176 @@ + + + macRachAttemptEvent + + 3366 + urn:oma:lwm2m:ext:3366 + 1.0 + 1.0 + Single + Optional + + rachAttemptCounter + R + Single + Mandatory + Integer + + + + + MacRachAttemptEventType + R + Single + Mandatory + Integer + + + + + contentionBased + R + Single + Mandatory + Boolean + + + + + rachMessage + R + Single + Mandatory + Integer + + + + + preambleIndex + R + Single + Mandatory + Integer + + + + + preamblePowerOffset + R + Single + Mandatory + Integer + + + + + backoffTime + R + Single + Mandatory + Integer + + + + + msg2Result + R + Single + Mandatory + Boolean + + + + + timingAdjustmentValue + R + Single + Mandatory + Integer + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3367.xml b/common/transport/lwm2m/src/main/resources/models/3367.xml new file mode 100644 index 0000000000..1f35cf4cc5 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3367.xml @@ -0,0 +1,138 @@ + + + macRachAttemptReasonEvent + + 3367 + urn:oma:lwm2m:ext:3367 + 1.0 + 1.0 + Single + Optional + + MacRachAttemptReasonType + R + Single + Mandatory + Integer + + + + + ueID + R + Single + Mandatory + Integer + + + + + contentionBased + R + Single + Mandatory + Boolean + + + + + preamble + R + Single + Mandatory + Integer + + + + + preambleGroupChosen + R + Single + Mandatory + Boolean + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3368.xml b/common/transport/lwm2m/src/main/resources/models/3368.xml new file mode 100644 index 0000000000..40c17bfd37 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3368.xml @@ -0,0 +1,100 @@ + + + macTimerStatusEvent + + 3368 + urn:oma:lwm2m:ext:3368 + 1.0 + 1.0 + Single + Optional + + macTimerName + R + Single + Mandatory + Integer + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3369.xml b/common/transport/lwm2m/src/main/resources/models/3369.xml new file mode 100644 index 0000000000..b93bb86644 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3369.xml @@ -0,0 +1,105 @@ + + + macTimingAdvanceEvent + + 3369 + urn:oma:lwm2m:ext:3369 + 1.0 + 1.0 + Single + Optional + + timerValue + R + Single + Mandatory + Integer + + + + + timingAdvance + R + Single + Mandatory + Integer + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3370.xml b/common/transport/lwm2m/src/main/resources/models/3370.xml new file mode 100644 index 0000000000..c79ff32a75 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3370.xml @@ -0,0 +1,141 @@ + + + ServingCellMeasurement + + 3370 + urn:oma:lwm2m:ext:3370 + 1.0 + 1.0 + Single + Optional + + sysFrameNumber + R + Single + Mandatory + Integer + + + + + subFrameNumber + R + Single + Mandatory + Integer + + + + + pci + R + Single + Mandatory + Integer + + + + + rsrp + R + Single + Mandatory + Integer + + + + + rsrq + R + Single + Mandatory + Integer + + + + + dlEarfcn + R + Single + Mandatory + Integer + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3371.xml b/common/transport/lwm2m/src/main/resources/models/3371.xml new file mode 100644 index 0000000000..8267b8ed81 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3371.xml @@ -0,0 +1,141 @@ + + + NeighborCellMeasurements + + 3371 + urn:oma:lwm2m:ext:3371 + 1.0 + 1.0 + Multiple + Optional + + sysFrameNumber + R + Single + Mandatory + Integer + + + + + subFrameNumber + R + Single + Mandatory + Integer + + + + + pci + R + Single + Mandatory + Integer + + + + + rsrp + R + Single + Mandatory + Integer + + + + + rsrq + R + Single + Mandatory + Integer + + + + + dlEarfcn + R + Single + Mandatory + Integer + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3372.xml b/common/transport/lwm2m/src/main/resources/models/3372.xml new file mode 100644 index 0000000000..d08c1dad3a --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3372.xml @@ -0,0 +1,115 @@ + + + TimingAdvance + + 3372 + urn:oma:lwm2m:ext:3372 + 1.0 + 1.0 + Single + Optional + + sysFrameNumber + R + Single + Mandatory + Integer + + + + + subFrameNumber + R + Single + Mandatory + Integer + + + + + timingAdvance + R + Single + Mandatory + Integer + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3373.xml b/common/transport/lwm2m/src/main/resources/models/3373.xml new file mode 100644 index 0000000000..9a4191787f --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3373.xml @@ -0,0 +1,115 @@ + + + txPowerHeadroomEvent + + 3373 + urn:oma:lwm2m:ext:3373 + 1.0 + 1.0 + Single + Optional + + sysFrameNumber + R + Single + Mandatory + Integer + + + + + subFrameNumber + R + Single + Mandatory + Integer + + + + + headroom-value + R + Single + Mandatory + Integer + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3374.xml b/common/transport/lwm2m/src/main/resources/models/3374.xml new file mode 100644 index 0000000000..abc9cc926f --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3374.xml @@ -0,0 +1,132 @@ + + + radioLinkMonitoring + + 3374 + urn:oma:lwm2m:ext:3374 + 1.0 + 1.0 + Single + Optional + + sysFrameNumber + R + Single + Mandatory + Integer + + + + + subFrameNumber + R + Single + Mandatory + Integer + + + + + outOfSyncCount + R + Single + Mandatory + Integer + + + + + inSyncCount + R + Single + Mandatory + Integer + + + + + t310Timer + R + Single + Mandatory + Boolean + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3375.xml b/common/transport/lwm2m/src/main/resources/models/3375.xml new file mode 100644 index 0000000000..e1df9f4851 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3375.xml @@ -0,0 +1,150 @@ + + + PagingDRX + + 3375 + urn:oma:lwm2m:ext:3375 + 1.0 + 1.0 + Single + Optional + + dlEarfcn + R + Single + Mandatory + Integer + + + + + pci + R + Single + Mandatory + Integer + + + + + pagingCycle + R + Single + Mandatory + Integer + + + + + DrxNb + R + Single + Mandatory + Integer + + + + + ueID + R + Single + Mandatory + Integer + + + + + drxSysFrameNumOffset + R + Single + Mandatory + Integer + + + + + drxSubFrameNumOffset + R + Single + Mandatory + Integer + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3376.xml b/common/transport/lwm2m/src/main/resources/models/3376.xml new file mode 100644 index 0000000000..542f816da0 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3376.xml @@ -0,0 +1,97 @@ + + + txPowerBackOffEvent + + 3376 + urn:oma:lwm2m:ext:3376 + 1.0 + 1.0 + Single + Optional + + TxPowerBackoff + R + Single + Mandatory + Integer + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3377.xml b/common/transport/lwm2m/src/main/resources/models/3377.xml new file mode 100644 index 0000000000..515eb36439 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3377.xml @@ -0,0 +1,168 @@ + + + Message3Report + + 3377 + urn:oma:lwm2m:ext:3377 + 1.0 + 1.0 + Single + Optional + + tpc + R + Single + Mandatory + Integer + + + + + resourceIndicatorValue + R + Single + Mandatory + Integer + + + + + cqi + R + Single + Mandatory + Integer + + + + + uplinkDelay + R + Single + Mandatory + Boolean + + + + + hoppingEnabled + R + Single + Mandatory + Boolean + + + + + numRb + R + Single + Mandatory + Integer + + + + + transportBlockSizeIndex + R + Single + Mandatory + Integer + + + + + ModulationType + R + Single + Mandatory + Integer + + + + + redundancyVersionIndex + R + Single + Mandatory + Integer + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3378.xml b/common/transport/lwm2m/src/main/resources/models/3378.xml new file mode 100644 index 0000000000..0855f5798a --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3378.xml @@ -0,0 +1,115 @@ + + + PbchDecodingResults + + 3378 + urn:oma:lwm2m:ext:3378 + 1.0 + 1.0 + Single + Optional + + servingCellID + R + Single + Mandatory + Integer + + + + + crcResult + R + Single + Mandatory + Boolean + + + + + sysFrameNumber + R + Single + Mandatory + Integer + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3379.xml b/common/transport/lwm2m/src/main/resources/models/3379.xml new file mode 100644 index 0000000000..0ac1648961 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3379.xml @@ -0,0 +1,123 @@ + + + pucchPowerControl + + 3379 + urn:oma:lwm2m:ext:3379 + 1.0 + 1.0 + Single + Optional + + sysFrameNumber + R + Single + Mandatory + Integer + + + + + subFrameNumber + R + Single + Mandatory + Integer + + + + + pucchTxPowerValue + + Single + Mandatory + Integer + + + + + dlPathLoss + R + Single + Mandatory + Integer + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3380-2_0.xml b/common/transport/lwm2m/src/main/resources/models/3380-2_0.xml new file mode 100644 index 0000000000..27545a6345 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3380-2_0.xml @@ -0,0 +1,204 @@ + + + PrachReport + + 3380 + urn:oma:lwm2m:ext:3380:2.0 + 1.0 + 2.0 + Single + Optional + + sysFrameNumber + R + Single + Mandatory + Integer + + + + + subFrameNumber + R + Single + Mandatory + Integer + + + + + rachTxPower + R + Single + Mandatory + Integer + + + + + zadOffSeqNum + R + Single + Mandatory + Integer + + + + + prachConfig + R + Single + Mandatory + Integer + + + + + preambleFormat + R + Single + Mandatory + Integer + + + + + maxTransmissionMsg3 + R + Single + Mandatory + Integer + + + + + raResponseWindowSize + R + Single + Mandatory + Integer + + + + + RachRequestResult + R + Single + Mandatory + Boolean + + + + + ce_mode + R + Single + Mandatory + Integer + + + + + ce_level + R + Single + Mandatory + Integer + + + + + num_prach_repetition + R + Single + Mandatory + Integer + + + + + prach_repetition_seq + R + Single + Mandatory + Integer + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3381.xml b/common/transport/lwm2m/src/main/resources/models/3381.xml new file mode 100644 index 0000000000..db2e4d52e8 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3381.xml @@ -0,0 +1,110 @@ + + + VolteCallEvent + + 3381 + urn:oma:lwm2m:ext:3381 + 1.0 + 1.0 + Single + Optional + + callStatus + R + Single + Mandatory + Integer + + + + + callType + R + Single + Mandatory + Integer + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3382.xml b/common/transport/lwm2m/src/main/resources/models/3382.xml new file mode 100644 index 0000000000..8f066837c8 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3382.xml @@ -0,0 +1,108 @@ + + + SipRegistrationEvent + + 3382 + urn:oma:lwm2m:ext:3382 + 1.0 + 1.0 + Single + Optional + + registrationType + R + Single + Mandatory + Integer + + + + + registrationResult + R + Single + Mandatory + Integer + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3383.xml b/common/transport/lwm2m/src/main/resources/models/3383.xml new file mode 100644 index 0000000000..663ac45faa --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3383.xml @@ -0,0 +1,99 @@ + + + sipPublishEvent + + 3383 + urn:oma:lwm2m:ext:3383 + 1.0 + 1.0 + Single + Optional + + publishResult + R + Single + Mandatory + Integer + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3384.xml b/common/transport/lwm2m/src/main/resources/models/3384.xml new file mode 100644 index 0000000000..a18c6b910b --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3384.xml @@ -0,0 +1,112 @@ + + + sipSubscriptionEvent + + 3384 + urn:oma:lwm2m:ext:3384 + 1.0 + 1.0 + Single + Optional + + eventType + R + Single + Mandatory + Integer + + + + + subscriptionResult + R + Single + Mandatory + Integer + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3385.xml b/common/transport/lwm2m/src/main/resources/models/3385.xml new file mode 100644 index 0000000000..cc0a99182a --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3385.xml @@ -0,0 +1,110 @@ + + + volteCallStateChangeEvent + + 3385 + urn:oma:lwm2m:ext:3385 + 1.0 + 1.0 + Single + Optional + + callStatus + R + Single + Mandatory + Integer + + + + + VolteCallStateChangeCause + R + Single + Mandatory + Integer + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/3386.xml b/common/transport/lwm2m/src/main/resources/models/3386.xml new file mode 100644 index 0000000000..43937efadb --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/3386.xml @@ -0,0 +1,105 @@ + + + VoLTErtpPacketLoss + 1]]> + 3386 + urn:oma:lwm2m:ext:3386 + 1.0 + 1.0 + Single + Optional + + ssrc + R + Single + Mandatory + Integer + + + + + packetsLost + R + Single + Mandatory + Integer + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/LWM2M_APN_Connection_Profile-v1_0_1.xml b/common/transport/lwm2m/src/main/resources/models/LWM2M_APN_Connection_Profile-v1_0_1.xml new file mode 100644 index 0000000000..924e822fc6 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/LWM2M_APN_Connection_Profile-v1_0_1.xml @@ -0,0 +1,324 @@ + + + + + LWM2M APN Connection Profile + + 11 + + urn:oma:lwm2m:oma:11 + 1.0 + 1.0 + Multiple + Optional + + Profile name + RW + Single + Mandatory + String + + + + + APN + RW + Single + Optional + String + + + + + Auto select APN by device + RW + Single + Optional + Boolean + + + + + Enable status + RW + Single + Optional + Boolean + + + + + Authentication Type + RW + Single + Mandatory + Integer + + + + + User Name + RW + Single + Optional + String + + + + + Secret + RW + Single + Optional + String + + + + + Reconnect Schedule + RW + Single + Optional + String + + + + + Validity (MCC, MNC) + RW + Multiple + Optional + String + + + + + Connection establishment time (1) + R + Multiple + Optional + Time + + + + + Connection establishment result (1) + R + Multiple + Optional + Integer + + + + + + Connection establishment reject cause (1) + R + Multiple + Optional + Integer + 0..111 + + + + Connection end time (1) + R + Multiple + Optional + Time + + + + + TotalBytesSent + R + Single + Optional + Integer + + + + + TotalBytesReceived + R + Single + Optional + Integer + + + + + IP address (2) + RW + Multiple + Optional + String + + + + + Prefix length(2) + RW + Multiple + Optional + String + + + + + Subnet mask (2) + RW + Multiple + Optional + String + + + + + Gateway (2) + RW + Multiple + Optional + String + + + + + Primary DNS address (2) + RW + Multiple + Optional + String + + + + + Secondary DNS address (2) + RW + Multiple + Optional + String + + + + + QCI (3) + R + Single + Optional + Integer + 1..9 + + + + Vendor specific extensions + R + Single + Optional + Objlnk + + + + + TotalPacketsSent + R + Single + Optional + Integer + + + + + PDN Type + RW + Single + Optional + Integer + + + + + + APN Rate Control + R + Single + Optional + Integer + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/LWM2M_Bearer_Selection-v1_0_1.xml b/common/transport/lwm2m/src/main/resources/models/LWM2M_Bearer_Selection-v1_0_1.xml new file mode 100644 index 0000000000..307df73553 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/LWM2M_Bearer_Selection-v1_0_1.xml @@ -0,0 +1,211 @@ + + + + + LWM2M Bearer Selection + + 13 + urn:oma:lwm2m:oma:13 + 1.0 + 1.0 + Single + Optional + + Preferred Communications Bearer + RW + Multiple + Optional + Integer + 8 bit + + + + Acceptable RSSI (GSM) + RW + Single + Optional + Integer + + + + + Acceptable RSCP (UMTS) + RW + Single + Optional + Integer + + + + + Acceptable RSRP (LTE) + RW + Single + Optional + Integer + + + + + Acceptable RSSI (1xEV-DO) + RW + Single + Optional + Integer + + + + + Cell lock list + RW + Single + Optional + String + + + + + Operator list + RW + Single + Optional + String + + + + + Operator list mode + RW + Single + Optional + Boolean + + + + + List of available PLMNs + R + Single + Optional + String + + + + + Vendor specific extensions + R + Single + Optional + Objlnk + + + + + Acceptable RSRP (NB-IoT) + RW + Single + Optional + Integer + + + + + Higher Priority PLMN Search Timer + RW + Single + Optional + Integer + + + + + Attach without PDN connection + RW + Single + Optional + Boolean + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/LWM2M_Cellular_Connectivity-v1_0_1.xml b/common/transport/lwm2m/src/main/resources/models/LWM2M_Cellular_Connectivity-v1_0_1.xml new file mode 100644 index 0000000000..45499202ba --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/LWM2M_Cellular_Connectivity-v1_0_1.xml @@ -0,0 +1,185 @@ + + + + + + LWM2M Cellular Connectivity + + 10 + urn:oma:lwm2m:oma:10 + 1.0 + 1.0 + Single + Optional + + SMSC address + RW + Single + Optional + String + + + + + Disable radio period + RW + Single + Optional + Integer + 0..65535 + + 0 the device SHALL disconnect. When the period has elapsed the device MAY reconnect.]]> + + Module activation code + RW + Single + Optional + String + + + + + Vendor specific extensions + R + Single + Optional + Objlnk + + + + + PSM Timer (1) + RW + Single + Optional + Integer + + s + + + Active Timer (1) + RW + Single + Optional + Integer + + s + + + Serving PLMN Rate control + R + Single + Optional + Integer + + + + + eDRX parameters for Iu mode (1) + RW + Single + Optional + Opaque + 8 bit + + + + eDRX parameters for WB-S1 mode (1) + RW + Single + Optional + Opaque + 8 bit + + + + eDRX parameters for NB-S1 mode (1) + RW + Single + Optional + Opaque + 8 bit + + + + eDRX parameters for A/Gb mode (1) + RW + Single + Optional + Opaque + 8 bit + + + + Activated Profile Names + R + Multiple + Mandatory + Objlnk + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/LWM2M_Connectivity_Monitoring-v1_0_2.xml b/common/transport/lwm2m/src/main/resources/models/LWM2M_Connectivity_Monitoring-v1_0_2.xml new file mode 100644 index 0000000000..28957f5a5d --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/LWM2M_Connectivity_Monitoring-v1_0_2.xml @@ -0,0 +1,208 @@ + + + + + Connectivity Monitoring + + This LwM2M Object enables monitoring of parameters related to network connectivity. In this general connectivity Object, the Resources are limited to the most general cases common to most network bearers. It is recommended to read the description, which refers to relevant standard development organizations (e.g. 3GPP, IEEE). The goal of the Connectivity Monitoring Object is to carry information reflecting the more up to date values of the current connection for monitoring purposes. Resources such as Link Quality, Radio Signal Strength, Cell ID are retrieved during connected mode at least for cellular networks. + + 4 + urn:oma:lwm2m:oma:4 + 1.0 + 1.0 + Single + Optional + + + Network Bearer + R + Single + Mandatory + Integer + 0-50 + + + Indicates the network bearer used for the current LwM2M communication session from the network bearer list below. The number range is split into three categories: 0 - 20 are Cellular Bearers 21 - 40 are Wireless Bearers 41 - 50 are Wireline Bearers More specifically: 0: GSM cellular network 1: TD-SCDMA cellular network 2: WCDMA cellular network 3: CDMA2000 cellular network 4: WiMAX cellular network 5: LTE-TDD cellular network 6: LTE-FDD cellular network 7: NB-IoT 8 - 20: Reserved for other types of cellular network 21: WLAN network 22: Bluetooth network 23: IEEE 802.15.4 network 24 - 40: Reserved for other types of local wireless network 41: Ethernet 42: DSL 43: PLC 44 - 50: reserved for other types of wireline networks. + + + + Available Network Bearer + R + Multiple + Mandatory + Integer + 0-50 + + + Indicates a list of current available network bearer. Each Resource Instance has a value from the network bearer list. + + + + Radio Signal Strength + R + Single + Mandatory + Integer + + dBm + + Indicates the average value of the received signal strength indication used in the current network bearer (as indicated by Resource 0 of this Object). For the following network bearers the signal strength parameters indicated below are represented by this resource: GSM: RSSI UMTS: RSCP LTE: RSRP NB-IoT: NRSRP For more details on Network Measurement Report, refer to the appropriate Cellular or Wireless Network standards, (e.g. for LTE Cellular Network refer to 3GPP TS 36.133 specification). + + + + Link Quality + R + Single + Optional + Integer + + + + This contains received link quality e.g. LQI for IEEE 802.15.4 (range 0...255), RxQual Downlink for GSM (range 0...7, refer to [3GPP 44.018] for more details on Network Measurement Report encoding), RSRQ for LTE, (refer to [3GPP 36.214]), NRSRQ for NB-IoT (refer to [3GPP 36.214]). + + + + IP Addresses + R + Multiple + Mandatory + String + + + + The IP addresses assigned to the connectivity interface. (e.g. IPv4, IPv6, etc.) + + + + Router IP Addresses + R + Multiple + Optional + String + + + + The IP address of the next-hop IP router, on each of the interfaces specified in resource 4 (IP Addresses). Note: This IP Address doesn’t indicate the Server IP address. + + + + Link Utilization + R + Single + Optional + Integer + 0-100 + % + + The percentage indicating the average utilization of the link to the next-hop IP router. + + + + APN + R + Multiple + Optional + String + + + + Access Point Name in case Network Bearer Resource is a Cellular Network. + + + + Cell ID + R + Single + Optional + Integer + + + + Serving Cell ID in case Network Bearer Resource is a Cellular Network. As specified in TS [3GPP 23.003] and in [3GPP. 24.008]. Range (0...65535) in GSM/EDGE UTRAN Cell ID has a length of 28 bits. Cell Identity in WCDMA/TD-SCDMA. Range: (0...268435455). LTE Cell ID has a length of 28 bits. Parameter definitions in [3GPP 25.331]. + + + + SMNC + R + Single + Optional + Integer + 0-999 + % + + Serving Mobile Network Code. This is applicable when the Network Bearer Resource value is referring to a cellular network. As specified in TS [3GPP 23.003]. + + + + SMCC + R + Single + Optional + Integer + 0-999 + + + Serving Mobile Country Code. This is applicable when the Network Bearer Resource value is referring to a cellular network. As specified in TS [3GPP 23.003]. + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/LWM2M_DevCapMgmt-v1_0.xml b/common/transport/lwm2m/src/main/resources/models/LWM2M_DevCapMgmt-v1_0.xml new file mode 100644 index 0000000000..6569894e18 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/LWM2M_DevCapMgmt-v1_0.xml @@ -0,0 +1,174 @@ + + + + + + + DevCapMgmt + + 15 + urn:oma:lwm2m:oma:15 + Multiple + Optional + + Property + R + Single + Mandatory + String + + + + + Group + R + Single + Mandatory + Integer + 0-15 + + + + Description + R + Single + Optional + String + + + + + Attached + R + Single + Optional + Boolean + + + + + Enabled + R + Single + Mandatory + Boolean + + + + + opEnable + E + Single + Mandatory + + + + + + opDisable + E + Multiple + Mandatory + + + + + + NotifyEn + RW + Single + Optional + Boolean + + + + + + + \ No newline at end of file diff --git a/common/transport/lwm2m/src/main/resources/models/LWM2M_LOCKWIPE-v1_0_1.xml b/common/transport/lwm2m/src/main/resources/models/LWM2M_LOCKWIPE-v1_0_1.xml new file mode 100644 index 0000000000..912add1a0a --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/LWM2M_LOCKWIPE-v1_0_1.xml @@ -0,0 +1,143 @@ + + + + + + + Lock and Wipe + + 8 + urn:oma:lwm2m:oma:8 + Single + Optional + + State + RW + Single + Mandatory + Integer + 0-2 + + + + Lock target + W + Multiple + Mandatory + String + + + + + Wipe item + R + Multiple + Optional + String + + + + + Wipe + E + Single + Mandatory + + + + + + + Wipe target + W + Multiple + Mandatory + String + + + + Lock or Wipe Operation Result + R + Single + Mandatory + Integer + 0-8 + + + + + + \ No newline at end of file diff --git a/common/transport/lwm2m/src/main/resources/models/LWM2M_Portfolio-v1_0.xml b/common/transport/lwm2m/src/main/resources/models/LWM2M_Portfolio-v1_0.xml new file mode 100644 index 0000000000..8147fc64a2 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/LWM2M_Portfolio-v1_0.xml @@ -0,0 +1,126 @@ + + + + + + + Portfolio + + 16 + urn:oma:lwm2m:oma:161.0 + 1.0Multiple + Optional + + Identity + RW + Multiple + Mandatory + String + + + + + GetAuthData + E + Single + Optional + + + + + + AuthData + R + Multiple + Optional + Opaque + + + + + AuthStatus + R + Single + Optional + Integer + [0-2] + + + + + + \ No newline at end of file diff --git a/common/transport/lwm2m/src/main/resources/models/LWM2M_Software_Component-v1_0.xml b/common/transport/lwm2m/src/main/resources/models/LWM2M_Software_Component-v1_0.xml new file mode 100644 index 0000000000..2cbdc8b76b --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/LWM2M_Software_Component-v1_0.xml @@ -0,0 +1,139 @@ + + + + + + + LWM2M Software Component + + 14 + urn:oma:lwm2m:oma:14 + Multiple + Optional + + + Component Identity + R + Single + Optional + String + 0-255 bytes + + + + + Component Pack + R + Single + Optional + Opaque + + + + + + Component Version + R + Single + Optional + String + 0-255 bytes + + + + + Activate + E + Single + Optional + + + + + + + Deactivate + E + Single + Optional + + + + + + Activation State + R + Single + Optional + Boolean + + + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/LWM2M_Software_Management-v1_0.xml b/common/transport/lwm2m/src/main/resources/models/LWM2M_Software_Management-v1_0.xml new file mode 100644 index 0000000000..33d9a62f4c --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/LWM2M_Software_Management-v1_0.xml @@ -0,0 +1,279 @@ + + + + + + + LWM2M Software Management + + 9 + urn:oma:lwm2m:oma:9 + Multiple + Optional + + + PkgName + R + Single + Mandatory + String + 0-255 bytes + + + + + PkgVersion + R + Single + Mandatory + String + 0-255 bytes + + + + + Package + W + Single + Optional + Opaque + + + + + + Package URI + W + Single + Optional + String + 0-255 bytes + + + + + Install + E + Single + Mandatory + + + + + + Checkpoint + R + Single + Optional + Objlnk + + + + + Uninstall + E + Single + Mandatory + + + + + + Update State + R + Single + Mandatory + Integer + 0-4 + + + + Update Supported Objects + RW + Single + Optional + Boolean + + + + + Update Result + R + Single + Mandatory + Integer + 0-200 + + + + Activate + E + Single + Mandatory + + + + + + Deactivate + E + Single + Mandatory + + + + + + Activation State + R + Single + Mandatory + Boolean + + + + + Package Settings + RW + Single + Optional + Objlnk + + + + + User Name + W + Single + Optional + String + 0-255 bytes + + + + Password + W + Single + Optional + String + 0-255 bytes + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/LWM2M_WLAN_connectivity4-v1_0.xml b/common/transport/lwm2m/src/main/resources/models/LWM2M_WLAN_connectivity4-v1_0.xml new file mode 100644 index 0000000000..71252b2b5c --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/LWM2M_WLAN_connectivity4-v1_0.xml @@ -0,0 +1,572 @@ + + + + + + + WLAN connectivity + + 12 + urn:oma:lwm2m:oma:12 + + + Multiple + Optional + + Interface name + RW + Single + Mandatory + String + + + + + Enable + RW + Single + Mandatory + Boolean + + + + + Radio Enabled + RW + Single + Optional + Integer + + + + + Status + R + Single + Mandatory + Integer + + + + + BSSID + R + Single + Mandatory + String + 12 bytes + + + + SSID + RW + Single + Mandatory + String + 1-32 Bytes + + + + Broadcast SSID + RW + Single + Optional + Boolean + + + + + Beacon Enabled + RW + Single + Optional + Boolean + + + + + Mode + RW + Single + Mandatory + Integer + + + + + Channel + RW + Single + Mandatory + Integer + 0-255 + + + + Auto Channel + RW + Single + Optional + Boolean + + + + + Supported Channels + RW + Multiple + Optional + Integer + + + + + Channels In Use + RW + Multiple + Optional + Integer + + + + + Regulatory Domain + RW + Single + Optional + String + 3 Bytes + + + + Standard + RW + Single + Mandatory + Integer + + + + + Authentication Mode + RW + Single + Mandatory + Integer + + + + + Encryption Mode + RW + Single + Optional + Integer + + + + + WPA Pre Shared Key + W + Single + Optional + String + 64 Bytes + + + + WPA Key Phrase + W + Single + Optional + String + 1-64 Bytes + + + + WEP Encryption Type + RW + Single + Optional + Integer + + + + + WEP Key Index + RW + Single + Optional + Integer + [1:4] + + + + WEP Key Phrase + W + Single + Optional + String + 1-64 Bytes + + + + WEP Key 1 + W + Single + Optional + String + 0 or 26 Bytes + + + + WEP Key 2 + W + Single + Optional + String + 0 or 26 Bytes + + + + WEP Key 3 + W + Single + Optional + String + 10 or 26 Bytes + + + + WEP Key 4 + W + Single + Optional + String + 10 or 26 Bytes + + + + RADIUS Server + RW + Single + Optional + String + 1-256 Bytes + + + + RADIUS Server Port + RW + Single + Optional + Integer + + + + + RADIUS Secret + W + Single + Optional + String + 1-256 Bytes + + + + WMM Supported + R + Single + Optional + Boolean + + + + + WMM Enabled + RW + Single + Optional + Boolean + + + + + MAC Control Enabled + RW + Single + Optional + Boolean + + + + + MAC Address List + RW + Multiple + Optional + String + 12 Bytes + + + + Total Bytes Sent + R + Single + Optional + Integer + + + + + Total Bytes Received + R + Single + Optional + Integer + + + + + Total Packets Sent + R + Single + Optional + Integer + + + + + Total Packets Received + R + Single + Optional + Integer + + + + + Transmit Errors + R + Single + Optional + Integer + + + + + Receive Errors + R + Single + Optional + Integer + + + + + Unicast Packets Sent + R + Single + Optional + Integer + + + + + Unicast Packets Received + R + Single + Optional + Integer + + + + + Multicast Packets Received + R + Single + Optional + Integer + + + + + Multicast Packets Received + R + Single + Optional + Integer + + + + + Broadcast Packets Sent + R + Single + Optional + Integer + + + + + 44 Broadcast Packets Received + R + Single + Optional + Integer + + + + + Discard Packets Sent + R + Single + Optional + Integer + + + + + Discard Packets Received + R + Single + Optional + Integer + + + + + Unknown Packets Received + R + Single + Optional + Integer + + + + + Vendor specific extensions + R + Single + Optional + Objlnk + + + + + + + \ No newline at end of file diff --git a/common/transport/lwm2m/src/main/resources/models/LwM2M_BinaryAppDataContainer-v1_0_1.xml b/common/transport/lwm2m/src/main/resources/models/LwM2M_BinaryAppDataContainer-v1_0_1.xml new file mode 100644 index 0000000000..b111d3b321 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/LwM2M_BinaryAppDataContainer-v1_0_1.xml @@ -0,0 +1,147 @@ + + + + + BinaryAppDataContainer + + 19 + urn:oma:lwm2m:oma:19 + 1.0 + 1.0 + Multiple + Optional + + Data + RW + + + + Multiple + Mandatory + Opaque + + + + + Data Priority + RW + Single + Optional + Integer + 1 bytes + + + + Data Creation Time + RW + Single + Optional + Time + + + + + Data Description + RW + Single + Optional + String + 32 bytes + + + + Data Format + RW + Single + Optional + String + 32 bytes + + + + App ID + RW + Single + Optional + Integer + 2 bytes + + + + + + diff --git a/common/transport/lwm2m/src/main/resources/models/LwM2M_EventLog-V1_0.xml b/common/transport/lwm2m/src/main/resources/models/LwM2M_EventLog-V1_0.xml new file mode 100644 index 0000000000..7cc3f918b2 --- /dev/null +++ b/common/transport/lwm2m/src/main/resources/models/LwM2M_EventLog-V1_0.xml @@ -0,0 +1,145 @@ + + + + + + + + Event Log + + 20 + urn:oma:lwm2m:oma:20 + 1.0 + 1.0 + Single + Optional + + LogClass + RW + Single + Optional + Integer + 255 + + + + LogStart + E + Single + Optional + + + + + + LogStop + E + Single + Optional + + + + + + LogStatus + R + Single + Optional + Integer + 8-Bits + + + + LogData + R + Single + Mandatory + Opaque + + + + + LogDataFormat + RW + Single + Optional + Integer + 255 + + + + + + \ No newline at end of file diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java index da93405e63..7ef9fd0ac2 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java @@ -102,4 +102,5 @@ public class GatewayDeviceSessionCtx extends MqttDeviceAwareSessionContext imple public void onToServerRpcResponse(TransportProtos.ToServerRpcResponseMsg toServerResponse) { // This feature is not supported in the TB IoT Gateway yet. } + } diff --git a/common/transport/pom.xml b/common/transport/pom.xml index b45d627444..6a54932ad0 100644 --- a/common/transport/pom.xml +++ b/common/transport/pom.xml @@ -39,6 +39,7 @@ mqtt http coap + lwm2m diff --git a/common/transport/transport-api/pom.xml b/common/transport/transport-api/pom.xml index eccbcaa902..87a4562f81 100644 --- a/common/transport/transport-api/pom.xml +++ b/common/transport/transport-api/pom.xml @@ -111,6 +111,12 @@ com.google.protobuf protobuf-java + + org.eclipse.leshan + leshan-core + 1.0.1 + compile + diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/SessionMsgListener.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/SessionMsgListener.java index 9eb0fbcd6c..ecafecadc4 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/SessionMsgListener.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/SessionMsgListener.java @@ -23,6 +23,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotif import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg; import org.thingsboard.server.gen.transport.TransportProtos.SessionCloseNotificationProto; import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcRequestMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToTransportUpdateCredentialsProto; import java.util.Optional; @@ -41,6 +42,8 @@ public interface SessionMsgListener { void onToServerRpcResponse(ToServerRpcResponseMsg toServerResponse); + default void onToTransportUpdateCredentials(ToTransportUpdateCredentialsProto toTransportUpdateCredentials){} + default void onDeviceProfileUpdate(TransportProtos.SessionInfoProto newSessionInfo, DeviceProfile deviceProfile) { } diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportService.java index 980aa33221..cec9eba5a1 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportService.java @@ -19,11 +19,14 @@ import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.transport.auth.GetOrCreateDeviceFromGatewayResponse; import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; +import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg; import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileResponseMsg; import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg; +import org.thingsboard.server.gen.transport.TransportProtos.LwM2MRequestMsg; +import org.thingsboard.server.gen.transport.TransportProtos.LwM2MResponseMsg; import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg; import org.thingsboard.server.gen.transport.TransportProtos.PostTelemetryMsg; import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg; @@ -36,6 +39,8 @@ import org.thingsboard.server.gen.transport.TransportProtos.SubscriptionInfoProt import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcResponseMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.ValidateBasicMqttCredRequestMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceLwM2MCredentialsRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceTokenRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509CertRequestMsg; @@ -55,12 +60,20 @@ public interface TransportService { void process(DeviceTransportType transportType, ValidateDeviceX509CertRequestMsg msg, TransportServiceCallback callback); + void process(ValidateDeviceLwM2MCredentialsRequestMsg msg, + TransportServiceCallback callback); + void process(GetOrCreateDeviceFromGatewayRequestMsg msg, TransportServiceCallback callback); void process(ProvisionDeviceRequestMsg msg, TransportServiceCallback callback); + void onProfileUpdate(DeviceProfile deviceProfile); + + void process(LwM2MRequestMsg msg, + TransportServiceCallback callback); + void process(SessionInfoProto sessionInfo, SessionEventMsg msg, TransportServiceCallback callback); void process(SessionInfoProto sessionInfo, PostTelemetryMsg msg, TransportServiceCallback callback); diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigBootstrap.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigBootstrap.java new file mode 100644 index 0000000000..2e8a00bc5e --- /dev/null +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigBootstrap.java @@ -0,0 +1,96 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.transport.lwm2m; + +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Component; +import org.thingsboard.server.gen.transport.TransportProtos; + +import java.security.PublicKey; +import java.security.cert.X509Certificate; +import java.util.Map; + +@Slf4j +@Component +@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true') || '${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core'") +public class LwM2MTransportConfigBootstrap { + + + @Getter + @Value("${transport.lwm2m.bootstrap.bind_address:}") + private String bootstrapHost; + + @Getter + @Value("${transport.lwm2m.bootstrap.bind_port:}") + private Integer bootstrapPort; + + @Getter + @Value("${transport.lwm2m.bootstrap.bind_port_cert:}") + private Integer bootstrapPortCert; + + + @Getter + @Value("${transport.lwm2m.bootstrap.secure.start_all:}") + private boolean bootstrapStartAll; + + @Getter + @Value("${transport.lwm2m.bootstrap.secure.dtls_mode:}") + private Integer bootStrapDtlsMode; + + @Getter + @Value("${transport.lwm2m.bootstrap.secure.bind_address:}") + private String bootstrapSecureHost; + + @Getter + @Value("${transport.lwm2m.bootstrap.secure.bind_port:}") + private Integer bootstrapSecurePort; + + @Getter + @Value("${transport.lwm2m.bootstrap.secure.bind_port_cert:}") + private Integer bootstrapSecurePortCert; + + @Getter + @Value("${transport.lwm2m.bootstrap.secure.public_x:}") + private String bootstrapPublicX; + + @Getter + @Value("${transport.lwm2m.bootstrap.secure.public_y:}") + private String bootstrapPublicY; + + @Getter + @Setter + private PublicKey bootstrapPublicKey; + + @Getter + @Value("${transport.lwm2m.bootstrap.secure.private_s:}") + private String bootstrapPrivateS; + + @Getter + @Value("${transport.lwm2m.bootstrap.secure.alias:}") + private String bootstrapAlias; + + @Getter + @Setter + private X509Certificate bootstrapCertificate; + + @Getter + @Setter + private Map sessions; +} diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigServer.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigServer.java new file mode 100644 index 0000000000..d8f305a049 --- /dev/null +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigServer.java @@ -0,0 +1,241 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.transport.lwm2m; + +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.model.ObjectLoader; +import org.eclipse.leshan.core.model.ObjectModel; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.io.*; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.util.List; + +@Slf4j +@Component +@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true') || '${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core'") +public class LwM2MTransportConfigServer { + + @Getter + @Value("${transport.lwm2m.timeout:}") + private Long timeout; + + @Getter + @Value("${transport.sessions.report_timeout}") + private long sessionReportTimeout; + + @Getter + private String MODEL_PATH_DEFAULT = "models"; + + @Getter + private String KEY_STORE_DEFAULT_RESOURCE_PATH = "credentials"; + + @Getter + private String KEY_STORE_DEFAULT_FILE = "serverKeyStore.jks"; + + @Getter + private String APP_DIR = "common"; + + @Getter + private String TRANSPORT_DIR = "transport"; + + @Getter + private String LWM2M_DIR = "lwm2m"; + + @Getter + private String SRC_DIR = "src"; + + @Getter + private String MAIN_DIR = "main"; + + @Getter + private String RESOURCES_DIR = "resources"; + + @Getter + private String BASE_DIR_PATH = System.getProperty("user.dir"); + + @Getter + @Value("${transport.lwm2m.model_path_file:}") + private String modelPathFile; + + @Getter +// private String PATH_DATA_MICROSERVICE = "/usr/share/tb-lwm2m-transport/data$"; + private String PATH_DATA = "data"; + + @Getter + @Setter + private List modelsValue; + + @Getter + @Value("${transport.lwm2m.support_deprecated_ciphers_enable:}") + private boolean supportDeprecatedCiphersEnable; + + @Getter + @Value("${transport.lwm2m.secure.key_store_type:}") + private String keyStoreType; + + @Getter + @Value("${transport.lwm2m.secure.key_store_path_file:}") + private String keyStorePathFile; + + @Getter + @Setter + private KeyStore keyStoreValue; + + @Getter + @Value("${transport.lwm2m.secure.key_store_password:}") + private String keyStorePasswordServer; + + @Getter + @Value("${transport.lwm2m.secure.root_alias:}") + private String rootAlias; + + @Getter + @Value("${transport.lwm2m.secure.enable_gen_psk_rpk:}") + private Boolean enableGenPskRpk; + + @Getter + @Value("${transport.lwm2m.server.bind_address:}") + private String serverHost; + + @Getter + @Value("${transport.lwm2m.server.bind_port:}") + private Integer serverPort; + + @Getter + @Value("${transport.lwm2m.server.bind_port_cert:}") + private Integer serverPortCert; + + @Getter + @Value("${transport.lwm2m.server.secure.start_all:}") + private boolean serverStartAll; + + @Getter + @Value("${transport.lwm2m.server.secure.dtls_mode:}") + private Integer serverDtlsMode; + + @Getter + @Value("${transport.lwm2m.server.secure.bind_address:}") + private String serverSecureHost; + + @Getter + @Value("${transport.lwm2m.server.secure.bind_port:}") + private Integer serverSecurePort; + + @Getter + @Value("${transport.lwm2m.server.secure.bind_port_cert:}") + private Integer serverSecurePortCert; + + @Getter + @Value("${transport.lwm2m.server.secure.public_x:}") + private String serverPublicX; + + @Getter + @Value("${transport.lwm2m.server.secure.public_y:}") + private String serverPublicY; + + @Getter + @Value("${transport.lwm2m.server.secure.private_s:}") + private String serverPrivateS; + + @Getter + @Value("${transport.lwm2m.server.secure.alias:}") + private String serverAlias; + + @Getter + @Value("${transport.lwm2m.bootstrap.enable:}") + private Boolean bootstrapEnable; + + @Getter + @Value("${transport.lwm2m.secure.redis_url:}") + private String redisUrl; + + @PostConstruct + public void init() { + modelsValue = ObjectLoader.loadDefault(); + File path = getPathModels(); + if (path.isDirectory()) { + try { + modelsValue.addAll(ObjectLoader.loadObjectsFromDir(path)); + log.info(" [{}] Models directory is a directory", path.getAbsoluteFile()); + } catch (Exception e) { + log.error(" [{}] Could not parse the resource definition file", e.toString()); + } + } else { + log.error(" [{}] Read Models", path.getAbsoluteFile()); + } + getInKeyStore(); + } + + private File getPathModels() { + Path pathModels = (modelPathFile != null && !modelPathFile.isEmpty()) ? Paths.get(modelPathFile) : + (new File(Paths.get(getBaseDirPath(), PATH_DATA, MODEL_PATH_DEFAULT).toUri()).isDirectory()) ? + Paths.get(getBaseDirPath(), PATH_DATA, MODEL_PATH_DEFAULT) : + Paths.get(getBaseDirPath(), APP_DIR, TRANSPORT_DIR, LWM2M_DIR, SRC_DIR, MAIN_DIR, RESOURCES_DIR, MODEL_PATH_DEFAULT); + return (pathModels != null) ? new File(pathModels.toUri()) : null; + } + + private KeyStore getInKeyStore() { + try { + if (keyStoreValue != null && keyStoreValue.size() > 0) + return keyStoreValue; + } catch (KeyStoreException e) { + log.error("Uninitialized keystore [{}]", keyStoreValue.toString()); + } + Path keyStorePath = (keyStorePathFile != null && !keyStorePathFile.isEmpty()) ? Paths.get(keyStorePathFile) : + (new File(Paths.get(getBaseDirPath(), PATH_DATA, KEY_STORE_DEFAULT_RESOURCE_PATH, KEY_STORE_DEFAULT_FILE).toUri()).isFile()) ? + Paths.get(getBaseDirPath(), PATH_DATA, KEY_STORE_DEFAULT_RESOURCE_PATH, KEY_STORE_DEFAULT_FILE) : + Paths.get(getBaseDirPath(), APP_DIR, TRANSPORT_DIR, LWM2M_DIR, SRC_DIR, MAIN_DIR, RESOURCES_DIR, KEY_STORE_DEFAULT_RESOURCE_PATH, KEY_STORE_DEFAULT_FILE); + File keyStoreFile = new File(keyStorePath.toUri()); + if (keyStoreFile.isFile()) { + try { + InputStream inKeyStore = new FileInputStream(keyStoreFile); + keyStoreValue = KeyStore.getInstance(keyStoreType); + keyStoreValue.load(inKeyStore, keyStorePasswordServer == null ? null : keyStorePasswordServer.toCharArray()); + } catch (CertificateException | NoSuchAlgorithmException | IOException | KeyStoreException e) { + log.error("[{}] Unable to load KeyStore files server, folder is not a directory", e.getMessage()); + keyStoreValue = null; + } + log.info("[{}] Load KeyStore files server, folder is a directory", keyStoreFile.getAbsoluteFile()); + } else { + log.error("[{}] Unable to load KeyStore files server, is not a file", keyStoreFile.getAbsoluteFile()); + keyStoreValue = null; + } + return keyStoreValue; + } + + private String getBaseDirPath() { + Path FULL_FILE_PATH; + if (BASE_DIR_PATH.endsWith("bin")) { + FULL_FILE_PATH = Paths.get(BASE_DIR_PATH.replaceAll("bin$", "")); + } else if (BASE_DIR_PATH.endsWith("conf")) { + FULL_FILE_PATH = Paths.get(BASE_DIR_PATH.replaceAll("conf$", "")); + } else { + FULL_FILE_PATH = Paths.get(BASE_DIR_PATH); + } + return FULL_FILE_PATH.toUri().getPath(); + } +} diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportDeviceProfileCache.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportDeviceProfileCache.java index b12aab1a8c..edf0ad2339 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportDeviceProfileCache.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportDeviceProfileCache.java @@ -17,27 +17,41 @@ package org.thingsboard.server.common.transport.service; import com.google.protobuf.ByteString; import lombok.extern.slf4j.Slf4j; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.DeviceProfile; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.transport.TransportDeviceProfileCache; +import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; +import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbTransportComponent; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; @Slf4j @Component @TbTransportComponent public class DefaultTransportDeviceProfileCache implements TransportDeviceProfileCache { + private final Lock deviceProfileFetchLock = new ReentrantLock(); private final ConcurrentMap deviceProfiles = new ConcurrentHashMap<>(); - private final DataDecodingEncodingService dataDecodingEncodingService; + private TransportService transportService; + + @Lazy + @Autowired + public void setTransportService(TransportService transportService) { + this.transportService = transportService; + } + public DefaultTransportDeviceProfileCache(DataDecodingEncodingService dataDecodingEncodingService) { this.dataDecodingEncodingService = dataDecodingEncodingService; } @@ -57,7 +71,7 @@ public class DefaultTransportDeviceProfileCache implements TransportDeviceProfil @Override public DeviceProfile get(DeviceProfileId id) { - return deviceProfiles.get(id); + return this.getDeviceProfile(id); } @Override @@ -80,4 +94,31 @@ public class DefaultTransportDeviceProfileCache implements TransportDeviceProfil public void evict(DeviceProfileId id) { deviceProfiles.remove(id); } + + + private DeviceProfile getDeviceProfile(DeviceProfileId id) { + DeviceProfile profile = deviceProfiles.get(id); + if (profile == null) { + deviceProfileFetchLock.lock(); + try { + TransportProtos.GetEntityProfileRequestMsg msg = TransportProtos.GetEntityProfileRequestMsg.newBuilder() + .setEntityType(EntityType.DEVICE_PROFILE.name()) + .setEntityIdMSB(id.getId().getMostSignificantBits()) + .setEntityIdLSB(id.getId().getLeastSignificantBits()) + .build(); + TransportProtos.GetEntityProfileResponseMsg entityProfileMsg = transportService.getEntityProfile(msg); + Optional profileOpt = dataDecodingEncodingService.decode(entityProfileMsg.getData().toByteArray()); + if (profileOpt.isPresent()) { + profile = profileOpt.get(); + this.put(profile); + } else { + log.warn("[{}] Can't device profile: {}", id, entityProfileMsg.getData()); + throw new RuntimeException("Can't device profile!"); + } + } finally { + deviceProfileFetchLock.unlock(); + } + } + return profile; + } } diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java index 3e619f8d6a..246ad7c7c0 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java @@ -193,6 +193,7 @@ public class DefaultTransportService implements TransportService { } records.forEach(record -> { try { + log.info("[{}] SessionIdMSB, [{}] SessionIdLSB, records", record.getValue().getSessionIdMSB(), record.getValue().getSessionIdLSB()); processToTransportMsg(record.getValue()); } catch (Throwable e) { log.warn("Failed to process the notification.", e); @@ -267,6 +268,13 @@ public class DefaultTransportService implements TransportService { } @Override + public void process(TransportProtos.ValidateDeviceLwM2MCredentialsRequestMsg msg, TransportServiceCallback callback) { + log.trace("Processing msg: {}", msg); + TbProtoQueueMsg protoMsg = new TbProtoQueueMsg<>(UUID.randomUUID(), TransportApiRequestMsg.newBuilder().setValidateDeviceLwM2MCredentialsRequestMsg(msg).build()); + AsyncCallbackTemplate.withCallback(transportApiRequestTemplate.send(protoMsg), + response -> callback.onSuccess(response.getValue().getValidateCredResponseMsg()), callback::onError, transportCallbackExecutor); + } + public void process(DeviceTransportType transportType, TransportProtos.ValidateDeviceX509CertRequestMsg msg, TransportServiceCallback callback) { log.trace("Processing msg: {}", msg); TbProtoQueueMsg protoMsg = new TbProtoQueueMsg<>(UUID.randomUUID(), TransportApiRequestMsg.newBuilder().setValidateX509CertRequestMsg(msg).build()); @@ -318,6 +326,15 @@ public class DefaultTransportService implements TransportService { AsyncCallbackTemplate.withCallback(response, callback::onSuccess, callback::onError, transportCallbackExecutor); } + @Override + public void process(TransportProtos.LwM2MRequestMsg msg, TransportServiceCallback callback) { + log.trace("Processing msg: {}", msg); + TbProtoQueueMsg protoMsg = new TbProtoQueueMsg<>(UUID.randomUUID(), + TransportApiRequestMsg.newBuilder().setLwM2MRequestMsg(msg).build()); + AsyncCallbackTemplate.withCallback(transportApiRequestTemplate.send(protoMsg), + response -> callback.onSuccess(response.getValue().getLwM2MResponseMsg()), callback::onError, transportCallbackExecutor); + } + private TransportDeviceInfo getTransportDeviceInfo(TransportProtos.DeviceInfoProto di) { TransportDeviceInfo tdi = new TransportDeviceInfo(); tdi.setTenantId(new TenantId(new UUID(di.getTenantIdMSB(), di.getTenantIdLSB()))); @@ -339,6 +356,7 @@ public class DefaultTransportService implements TransportService { AsyncCallbackTemplate.withCallback(response, callback::onSuccess, callback::onError, transportCallbackExecutor); } + @Override public void process(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.SubscriptionInfoProto msg, TransportServiceCallback callback) { if (log.isTraceEnabled()) { @@ -605,6 +623,9 @@ public class DefaultTransportService implements TransportService { if (toSessionMsg.hasSessionCloseNotification()) { listener.onRemoteSessionCloseCommand(toSessionMsg.getSessionCloseNotification()); } + if (toSessionMsg.hasToTransportUpdateCredentialsNotification()) { + listener.onToTransportUpdateCredentials(toSessionMsg.getToTransportUpdateCredentialsNotification()); + } if (toSessionMsg.hasToDeviceRequest()) { listener.onToDeviceRpcRequest(toSessionMsg.getToDeviceRequest()); } @@ -668,7 +689,7 @@ public class DefaultTransportService implements TransportService { } } - private void onProfileUpdate(DeviceProfile deviceProfile) { + public void onProfileUpdate(DeviceProfile deviceProfile) { long deviceProfileIdMSB = deviceProfile.getId().getId().getMostSignificantBits(); long deviceProfileIdLSB = deviceProfile.getId().getId().getLeastSignificantBits(); sessions.forEach((id, md) -> { diff --git a/docker/.env b/docker/.env index b632300d5f..f7b30aafe0 100644 --- a/docker/.env +++ b/docker/.env @@ -8,6 +8,7 @@ WEB_UI_DOCKER_NAME=tb-web-ui MQTT_TRANSPORT_DOCKER_NAME=tb-mqtt-transport HTTP_TRANSPORT_DOCKER_NAME=tb-http-transport COAP_TRANSPORT_DOCKER_NAME=tb-coap-transport +LWM2M_TRANSPORT_DOCKER_NAME=tb-lwm2m-transport TB_VERSION=latest diff --git a/docker/docker-compose.aws-sqs.yml b/docker/docker-compose.aws-sqs.yml index e58917043b..756ae11249 100644 --- a/docker/docker-compose.aws-sqs.yml +++ b/docker/docker-compose.aws-sqs.yml @@ -68,4 +68,9 @@ services: env_file: - queue-aws-sqs.env depends_on: - - zookeeper \ No newline at end of file + - zookeeper + tb-lwm2m-transport: + env_file: + - queue-aws-sqs.env + depends_on: + - zookeeper diff --git a/docker/docker-compose.confluent.yml b/docker/docker-compose.confluent.yml index 1bbc3f96d6..e16059ea9a 100644 --- a/docker/docker-compose.confluent.yml +++ b/docker/docker-compose.confluent.yml @@ -55,3 +55,6 @@ services: tb-coap-transport: env_file: - queue-confluent.env + tb-lwm2m-transport: + env_file: + - queue-confluent.env diff --git a/docker/docker-compose.kafka.yml b/docker/docker-compose.kafka.yml index c9b235008b..2b345b5210 100644 --- a/docker/docker-compose.kafka.yml +++ b/docker/docker-compose.kafka.yml @@ -80,3 +80,8 @@ services: - queue-kafka.env depends_on: - kafka + tb-lwm2m-transport: + env_file: + - queue-kafka.env + depends_on: + - kafka diff --git a/docker/docker-compose.postgres.volumes.yml b/docker/docker-compose.postgres.volumes.yml index caaacf96e8..45819c4a66 100644 --- a/docker/docker-compose.postgres.volumes.yml +++ b/docker/docker-compose.postgres.volumes.yml @@ -35,6 +35,9 @@ services: tb-coap-transport: volumes: - tb-coap-transport-log-volume:/var/log/tb-coap-transport + tb-lwm2m-transport: + volumes: + - tb-lwm2m-transport-log-volume:/var/log/tb-lwm2m-transport tb-http-transport1: volumes: - tb-http-transport-log-volume:/var/log/tb-http-transport @@ -58,6 +61,9 @@ volumes: tb-coap-transport-log-volume: external: true name: ${TB_COAP_TRANSPORT_LOG_VOLUME} + tb-lwm2m-transport-log-volume: + external: true + name: ${TB_LWM2M_TRANSPORT_LOG_VOLUME} tb-http-transport-log-volume: external: true name: ${TB_HTTP_TRANSPORT_LOG_VOLUME} diff --git a/docker/docker-compose.pubsub.yml b/docker/docker-compose.pubsub.yml index 93b4047a5d..13f9078b99 100644 --- a/docker/docker-compose.pubsub.yml +++ b/docker/docker-compose.pubsub.yml @@ -69,3 +69,8 @@ services: - queue-pubsub.env depends_on: - zookeeper + tb-lwm2m-transport: + env_file: + - queue-pubsub.env + depends_on: + - zookeeper diff --git a/docker/docker-compose.rabbitmq.yml b/docker/docker-compose.rabbitmq.yml index 06662b39b6..105833caa3 100644 --- a/docker/docker-compose.rabbitmq.yml +++ b/docker/docker-compose.rabbitmq.yml @@ -68,4 +68,9 @@ services: env_file: - queue-rabbitmq.env depends_on: - - zookeeper \ No newline at end of file + - zookeeper + tb-lwm2m-transport: + env_file: + - queue-rabbitmq.env + depends_on: + - zookeeper diff --git a/docker/docker-compose.service-bus.yml b/docker/docker-compose.service-bus.yml index 01dd863792..f24c0ee55b 100644 --- a/docker/docker-compose.service-bus.yml +++ b/docker/docker-compose.service-bus.yml @@ -67,5 +67,8 @@ services: tb-coap-transport: env_file: - queue-service-bus.env + tb-lwm2m-transport: + env_file: + - queue-service-bus.env depends_on: - - zookeeper \ No newline at end of file + - zookeeper diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index fbb8ee262d..36a658b5da 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -199,6 +199,20 @@ services: - ./tb-transports/coap/log:/var/log/tb-coap-transport depends_on: - zookeeper + tb-lwm2m-transport: + restart: always + image: "${DOCKER_REPO}/${LWM2M_TRANSPORT_DOCKER_NAME}:${TB_VERSION}" + ports: + - "5685:5685/udp" + environment: + TB_SERVICE_ID: tb-lwm2m-transport + env_file: + - tb-lwm2m-transport.env + volumes: + - ./tb-transports/lwm2m/conf:/config + - ./tb-transports/lwm2m/log:/var/log/tb-lwm2m-transport + depends_on: + - zookeeper tb-web-ui1: restart: always image: "${DOCKER_REPO}/${WEB_UI_DOCKER_NAME}:${TB_VERSION}" diff --git a/docker/docker-create-log-folders.sh b/docker/docker-create-log-folders.sh index 1ac4539b30..bee0b7809e 100755 --- a/docker/docker-create-log-folders.sh +++ b/docker/docker-create-log-folders.sh @@ -19,6 +19,8 @@ mkdir -p tb-node/log/ && sudo chown -R 799:799 tb-node/log/ mkdir -p tb-transports/coap/log && sudo chown -R 799:799 tb-transports/coap/log +mkdir -p tb-transports/lwm2m/log && sudo chown -R 799:799 tb-transports/lwm2m/log + mkdir -p tb-transports/http/log && sudo chown -R 799:799 tb-transports/http/log -mkdir -p tb-transports/mqtt/log && sudo chown -R 799:799 tb-transports/mqtt/log \ No newline at end of file +mkdir -p tb-transports/mqtt/log && sudo chown -R 799:799 tb-transports/mqtt/log diff --git a/docker/tb-lwm2m-transport.env b/docker/tb-lwm2m-transport.env new file mode 100644 index 0000000000..6e6cad922b --- /dev/null +++ b/docker/tb-lwm2m-transport.env @@ -0,0 +1,6 @@ +ZOOKEEPER_ENABLED=true +ZOOKEEPER_URL=zookeeper:2181 + +LWM2M_BIND_ADDRESS=0.0.0.0 +LWM2M_BIND_PORT=5685 +LWM2M_TIMEOUT=10000 diff --git a/docker/tb-transports/lwm2m/conf/logback.xml b/docker/tb-transports/lwm2m/conf/logback.xml new file mode 100644 index 0000000000..199e138fc1 --- /dev/null +++ b/docker/tb-transports/lwm2m/conf/logback.xml @@ -0,0 +1,50 @@ + + + + + + + /var/log/tb-lwm2m-transport/${TB_SERVICE_ID}/tb-lwm2m-transport.log + + /var/log/tb-lwm2m-transport/${TB_SERVICE_ID}/tb-lwm2m-transport.%d{yyyy-MM-dd}.%i.log + 100MB + 30 + 3GB + + + %d{ISO8601} [%thread] %-5level %logger{36} - %msg%n + + + + + + %d{ISO8601} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + diff --git a/docker/tb-transports/lwm2m/conf/tb-lwm2m-transport.conf b/docker/tb-transports/lwm2m/conf/tb-lwm2m-transport.conf new file mode 100644 index 0000000000..1ea46cd8bf --- /dev/null +++ b/docker/tb-transports/lwm2m/conf/tb-lwm2m-transport.conf @@ -0,0 +1,23 @@ +# +# Copyright © 2016-2020 The Thingsboard Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +export JAVA_OPTS="$JAVA_OPTS -Xloggc:/var/log/tb-lwm2m-transport/${TB_SERVICE_ID}/gc.log -XX:+IgnoreUnrecognizedVMOptions -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/tb-lwm2m-transport/${TB_SERVICE_ID}/heapdump.bin -XX:+PrintGCDetails -XX:+PrintGCDateStamps" +export JAVA_OPTS="$JAVA_OPTS -XX:+PrintHeapAtGC -XX:+PrintTenuringDistribution -XX:+PrintGCApplicationStoppedTime -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10" +export JAVA_OPTS="$JAVA_OPTS -XX:GCLogFileSize=10M -XX:-UseBiasedLocking -XX:+UseTLAB -XX:+ResizeTLAB -XX:+PerfDisableSharedMem -XX:+UseCondCardMark" +export JAVA_OPTS="$JAVA_OPTS -XX:CMSWaitDuration=10000 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+CMSParallelInitialMarkEnabled" +export JAVA_OPTS="$JAVA_OPTS -XX:+CMSEdenChunksRecordAlways -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly -XX:+ExitOnOutOfMemoryError" +export LOG_FILENAME=tb-lwm2m-transport.out +export LOADER_PATH=/usr/share/tb-lwm2m-transport/conf diff --git a/k8s/common/thingsboard.yml b/k8s/common/thingsboard.yml index af4ff0d678..de8bc71c91 100644 --- a/k8s/common/thingsboard.yml +++ b/k8s/common/thingsboard.yml @@ -265,6 +265,72 @@ spec: --- apiVersion: apps/v1 kind: Deployment +metadata: + name: tb-lwm2m-transport + namespace: thingsboard +spec: + replicas: 2 + selector: + matchLabels: + app: tb-lwm2m-transport + template: + metadata: + labels: + app: tb-lwm2m-transport + spec: + volumes: + - name: tb-lwm2m-transport-config + configMap: + name: tb-lwm2m-transport-config + items: + - key: conf + path: tb-lwm2m-transport.conf + - key: logback + path: logback.xml + containers: + - name: server + imagePullPolicy: Always + image: thingsboard/tb-lwm2m-transport:latest + ports: + - containerPort: 5685 + name: lwm2m + protocol: UDP + env: + - name: TB_SERVICE_ID + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: TB_QUEUE_TYPE + value: "kafka" + - name: LWM2M_BIND_ADDRESS + value: "0.0.0.0" + - name: LWM2M_BIND_PORT + value: "5685" + - name: LWM2M_TIMEOUT + value: "10000" + - name: TB_KAFKA_SERVERS + value: "tb-kafka:9092" + volumeMounts: + - mountPath: /config + name: tb-lwm2m-transport-config + restartPolicy: Always +--- +apiVersion: v1 +kind: Service +metadata: + name: tb-lwm2m-transport + namespace: thingsboard +spec: + type: LoadBalancer + selector: + app: tb-lwm2m-transport + ports: + - port: 5685 + name: lwm2m + protocol: UDP +--- +apiVersion: apps/v1 +kind: Deployment metadata: name: tb-web-ui namespace: thingsboard diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ThingsBoardDbInstaller.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ThingsBoardDbInstaller.java index d661bb7476..981b778016 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ThingsBoardDbInstaller.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ThingsBoardDbInstaller.java @@ -29,6 +29,7 @@ public class ThingsBoardDbInstaller extends ExternalResource { private final static String POSTGRES_DATA_VOLUME = "tb-postgres-test-data-volume"; private final static String TB_LOG_VOLUME = "tb-log-test-volume"; private final static String TB_COAP_TRANSPORT_LOG_VOLUME = "tb-coap-transport-log-test-volume"; + private final static String TB_LWM2M_TRANSPORT_LOG_VOLUME = "tb-lwm2m-transport-log-test-volume"; private final static String TB_HTTP_TRANSPORT_LOG_VOLUME = "tb-http-transport-log-test-volume"; private final static String TB_MQTT_TRANSPORT_LOG_VOLUME = "tb-mqtt-transport-log-test-volume"; @@ -37,6 +38,7 @@ public class ThingsBoardDbInstaller extends ExternalResource { private final String postgresDataVolume; private final String tbLogVolume; private final String tbCoapTransportLogVolume; + private final String tbLwm2mTransportLogVolume; private final String tbHttpTransportLogVolume; private final String tbMqttTransportLogVolume; private final Map env; @@ -52,6 +54,7 @@ public class ThingsBoardDbInstaller extends ExternalResource { postgresDataVolume = project + "_" + POSTGRES_DATA_VOLUME; tbLogVolume = project + "_" + TB_LOG_VOLUME; tbCoapTransportLogVolume = project + "_" + TB_COAP_TRANSPORT_LOG_VOLUME; + tbLwm2mTransportLogVolume = project + "_" + TB_LWM2M_TRANSPORT_LOG_VOLUME; tbHttpTransportLogVolume = project + "_" + TB_HTTP_TRANSPORT_LOG_VOLUME; tbMqttTransportLogVolume = project + "_" + TB_MQTT_TRANSPORT_LOG_VOLUME; @@ -61,6 +64,7 @@ public class ThingsBoardDbInstaller extends ExternalResource { env.put("POSTGRES_DATA_VOLUME", postgresDataVolume); env.put("TB_LOG_VOLUME", tbLogVolume); env.put("TB_COAP_TRANSPORT_LOG_VOLUME", tbCoapTransportLogVolume); + env.put("TB_LWM2M_TRANSPORT_LOG_VOLUME", tbLwm2mTransportLogVolume); env.put("TB_HTTP_TRANSPORT_LOG_VOLUME", tbHttpTransportLogVolume); env.put("TB_MQTT_TRANSPORT_LOG_VOLUME", tbMqttTransportLogVolume); dockerCompose.withEnv(env); @@ -83,6 +87,9 @@ public class ThingsBoardDbInstaller extends ExternalResource { dockerCompose.withCommand("volume create " + tbCoapTransportLogVolume); dockerCompose.invokeDocker(); + dockerCompose.withCommand("volume create " + tbLwm2mTransportLogVolume); + dockerCompose.invokeDocker(); + dockerCompose.withCommand("volume create " + tbHttpTransportLogVolume); dockerCompose.invokeDocker(); @@ -107,11 +114,12 @@ public class ThingsBoardDbInstaller extends ExternalResource { protected void after() { copyLogs(tbLogVolume, "./target/tb-logs/"); copyLogs(tbCoapTransportLogVolume, "./target/tb-coap-transport-logs/"); + copyLogs(tbLwm2mTransportLogVolume, "./target/tb-lwm2m-transport-logs/"); copyLogs(tbHttpTransportLogVolume, "./target/tb-http-transport-logs/"); copyLogs(tbMqttTransportLogVolume, "./target/tb-mqtt-transport-logs/"); dockerCompose.withCommand("volume rm -f " + postgresDataVolume + " " + tbLogVolume + - " " + tbCoapTransportLogVolume + " " + tbHttpTransportLogVolume + " " + tbMqttTransportLogVolume); + " " + tbCoapTransportLogVolume + " " + tbLwm2mTransportLogVolume + " " + tbHttpTransportLogVolume + " " + tbMqttTransportLogVolume); dockerCompose.invokeDocker(); } diff --git a/msa/tb/README.md b/msa/tb/README.md index 488ead2d85..6987c42bfa 100644 --- a/msa/tb/README.md +++ b/msa/tb/README.md @@ -21,7 +21,7 @@ In this example `thingsboard/tb` image will be used. You can choose any other im Execute the following command to run this docker directly: ` -$ docker run -it -p 9090:9090 -p 1883:1883 -p 5683:5683/udp -v ~/.mytb-data:/data --name mytb thingsboard/tb +$ docker run -it -p 9090:9090 -p 1883:1883 -p 5683:5683/udp -p 5685:5685/udp -v ~/.mytb-data:/data --name mytb thingsboard/tb ` Where: @@ -31,6 +31,7 @@ Where: - `-p 9090:9090` - connect local port 9090 to exposed internal HTTP port 9090 - `-p 1883:1883` - connect local port 1883 to exposed internal MQTT port 1883 - `-p 5683:5683` - connect local port 5683 to exposed internal COAP port 5683 +- `-p 5685:5685` - connect local port 5685 to exposed internal COAP port 5685 (lwm2m) - `-v ~/.mytb-data:/data` - mounts the host's dir `~/.mytb-data` to ThingsBoard DataBase data directory - `--name mytb` - friendly local name of this machine - `thingsboard/tb` - docker image, can be also `thingsboard/tb-postgres` or `thingsboard/tb-cassandra` @@ -45,6 +46,7 @@ Where: > $ VBoxManage controlvm "default" natpf1 "tcp-port9090,tcp,,9090,,9090" > $ VBoxManage controlvm "default" natpf1 "tcp-port1883,tcp,,1883,,1883" > $ VBoxManage controlvm "default" natpf1 "tcp-port5683,tcp,,5683,,5683" +> $ VBoxManage controlvm "default" natpf1 "tcp-port5683,tcp,,5685,,5685" > ``` After executing `docker run` command you can open `http://{your-host-ip}:9090` in you browser (for ex. `http://localhost:9090`). You should see ThingsBoard login page. diff --git a/msa/tb/docker-cassandra/Dockerfile b/msa/tb/docker-cassandra/Dockerfile index ebb52b0186..1f01d20ddc 100644 --- a/msa/tb/docker-cassandra/Dockerfile +++ b/msa/tb/docker-cassandra/Dockerfile @@ -93,6 +93,7 @@ USER ${pkg.user} EXPOSE 9090 EXPOSE 1883 EXPOSE 5683/udp +EXPOSE 5685/udp VOLUME ["/data"] diff --git a/msa/tb/docker-postgres/Dockerfile b/msa/tb/docker-postgres/Dockerfile index 0c4ef5ed68..edde576167 100644 --- a/msa/tb/docker-postgres/Dockerfile +++ b/msa/tb/docker-postgres/Dockerfile @@ -74,6 +74,7 @@ USER ${pkg.user} EXPOSE 9090 EXPOSE 1883 EXPOSE 5683/udp +EXPOSE 5685/udp VOLUME ["/data"] diff --git a/msa/tb/docker-tb/Dockerfile b/msa/tb/docker-tb/Dockerfile index 6e7d2a294a..da38870530 100644 --- a/msa/tb/docker-tb/Dockerfile +++ b/msa/tb/docker-tb/Dockerfile @@ -54,6 +54,7 @@ USER ${pkg.user} EXPOSE 9090 EXPOSE 1883 EXPOSE 5683/udp +EXPOSE 5685/udp VOLUME ["/data"] diff --git a/msa/transport/lwm2m/docker/Dockerfile b/msa/transport/lwm2m/docker/Dockerfile new file mode 100644 index 0000000000..cb79fb3fda --- /dev/null +++ b/msa/transport/lwm2m/docker/Dockerfile @@ -0,0 +1,33 @@ +# +# Copyright © 2016-2020 The Thingsboard Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +FROM thingsboard/openjdk8 + +COPY start-tb-lwm2m-transport.sh ${pkg.name}.deb /tmp/ + +RUN chmod a+x /tmp/*.sh \ + && mv /tmp/start-tb-lwm2m-transport.sh /usr/bin + +RUN yes | dpkg -i /tmp/${pkg.name}.deb +RUN rm /tmp/${pkg.name}.deb + +RUN systemctl --no-reload disable --now ${pkg.name}.service > /dev/null 2>&1 || : + +RUN chmod 555 ${pkg.installFolder}/bin/${pkg.name}.jar + +USER ${pkg.user} + +CMD ["start-tb-lwm2m-transport.sh"] diff --git a/msa/transport/lwm2m/docker/start-tb-lwm2m-transport.sh b/msa/transport/lwm2m/docker/start-tb-lwm2m-transport.sh new file mode 100755 index 0000000000..7fd12d330e --- /dev/null +++ b/msa/transport/lwm2m/docker/start-tb-lwm2m-transport.sh @@ -0,0 +1,33 @@ +#!/bin/bash +# +# Copyright © 2016-2020 The Thingsboard Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +CONF_FOLDER="/config" +jarfile=${pkg.installFolder}/bin/${pkg.name}.jar +configfile=${pkg.name}.conf + +source "${CONF_FOLDER}/${configfile}" + +export LOADER_PATH=/config,${LOADER_PATH} + +echo "Starting '${project.name}' ..." + +cd ${pkg.installFolder}/bin + +exec java -cp ${jarfile} $JAVA_OPTS -Dloader.main=org.thingsboard.server.lwm2m.ThingsboardLwm2mTransportApplication \ + -Dspring.jpa.hibernate.ddl-auto=none \ + -Dlogging.config=/config/logback.xml \ + org.springframework.boot.loader.PropertiesLauncher diff --git a/msa/transport/lwm2m/pom.xml b/msa/transport/lwm2m/pom.xml new file mode 100644 index 0000000000..039e50564a --- /dev/null +++ b/msa/transport/lwm2m/pom.xml @@ -0,0 +1,190 @@ + + + 4.0.0 + + org.thingsboard.msa + 3.2.0-SNAPSHOT + transport + + org.thingsboard.msa.transport + lwm2m + pom + + ThingsBoard LWM2M Transport Microservice + https://thingsboard.io + ThingsBoard LWM2M Transport Microservice + + + UTF-8 + ${basedir}/../../.. + tb-lwm2m-transport + tb-lwm2m-transport + /var/log/${pkg.name} + /usr/share/${pkg.name} + + + + + org.thingsboard.transport + lwm2m + ${project.version} + deb + deb + provided + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-tb-lwm2m-transport-deb + package + + copy + + + + + org.thingsboard.transport + lwm2m + deb + deb + ${pkg.name}.deb + ${project.build.directory} + + + + + + + + org.apache.maven.plugins + maven-resources-plugin + + + copy-docker-config + process-resources + + copy-resources + + + ${project.build.directory} + + + docker + true + + + + + + + + com.spotify + dockerfile-maven-plugin + + + build-docker-image + pre-integration-test + + build + + + ${dockerfile.skip} + ${docker.repo}/${docker.name} + true + false + ${project.build.directory} + + + + tag-docker-image + pre-integration-test + + tag + + + ${dockerfile.skip} + ${docker.repo}/${docker.name} + ${project.version} + + + + + + + + + push-docker-image + + + push-docker-image + + + + + + com.spotify + dockerfile-maven-plugin + + + push-latest-docker-image + pre-integration-test + + push + + + latest + ${docker.repo}/${docker.name} + + + + push-version-docker-image + pre-integration-test + + push + + + ${project.version} + ${docker.repo}/${docker.name} + + + + + + + + + + + jenkins + Jenkins Repository + https://repo.jenkins-ci.org/releases + + false + + + + + diff --git a/msa/transport/pom.xml b/msa/transport/pom.xml index befee6cdea..7875975685 100644 --- a/msa/transport/pom.xml +++ b/msa/transport/pom.xml @@ -38,6 +38,7 @@ mqtt http coap + lwm2m diff --git a/pom.xml b/pom.xml index eb49e8ed4c..d87cc038d5 100755 --- a/pom.xml +++ b/pom.xml @@ -62,7 +62,9 @@ 2.11.3 2.11.3 2.2.6 - 1.0.2 + 2.2.3 + 1.0.1 + 1.0.0 2.6.2 2.3.30 1.6.2 @@ -254,7 +256,8 @@ - ${main.dir}/packaging/${pkg.type}/filters/windows.properties + ${main.dir}/packaging/${pkg.type}/filters/windows.properties + @@ -315,7 +318,8 @@ - ${main.dir}/packaging/${pkg.type}/filters/windows.properties + ${main.dir}/packaging/${pkg.type}/filters/windows.properties + @@ -337,7 +341,8 @@ - ${main.dir}/packaging/${pkg.type}/filters/windows.properties + ${main.dir}/packaging/${pkg.type}/filters/windows.properties + @@ -361,9 +366,39 @@ false + + ../common/transport/lwm2m/src/main/resources + + **/*.xml + **/*.jks + + false + + + + + + copy-lwm2m-resources + ${pkg.process-resources.phase} + + copy-resources + + + ../transport/lwm2m/src/main/data + + + ../common/transport/lwm2m/src/main/resources + + **/*.xml + **/*.jks + + false + + + copy-docker-config ${pkg.process-resources.phase} @@ -728,6 +763,10 @@ **/*.proto.js docker/haproxy/** docker/tb-node/** + src/main/resources/models/*.xml + src/main/resources/credentials/*.jks + src/main/resources/credentials/shell/*.jks + src/main/resources/credentials/shell/*.jks.old ui/** src/browserslist **/*.raw @@ -837,6 +876,11 @@ coap ${project.version} + + org.thingsboard.common.transport + lwm2m + ${project.version} + org.thingsboard dao @@ -1101,6 +1145,21 @@ + + org.eclipse.leshan + leshan-server-cf + ${leshan-server.version} + + + org.eclipse.leshan + leshan-client-cf + ${leshan-client.version} + + + org.eclipse.leshan + leshan-server-redis + ${leshan-server.version} + org.eclipse.californium californium-core diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/msg/DeviceCredentialsUpdateNotificationMsg.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/msg/DeviceCredentialsUpdateNotificationMsg.java index 356fd5db0f..f34459070e 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/msg/DeviceCredentialsUpdateNotificationMsg.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/msg/DeviceCredentialsUpdateNotificationMsg.java @@ -21,6 +21,8 @@ import lombok.ToString; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.kv.AttributeKey; +import org.thingsboard.server.common.data.security.DeviceCredentials; +import org.thingsboard.server.common.data.security.DeviceCredentialsType; import org.thingsboard.server.common.msg.MsgType; import java.util.Set; @@ -34,6 +36,12 @@ public class DeviceCredentialsUpdateNotificationMsg implements ToDeviceActorNoti private final TenantId tenantId; private final DeviceId deviceId; + /** + * LwM2M + * @return + */ + private final DeviceCredentials deviceCredentials; + @Override public MsgType getMsgType() { return MsgType.DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG; diff --git a/transport/lwm2m/pom.xml b/transport/lwm2m/pom.xml new file mode 100644 index 0000000000..23e037451a --- /dev/null +++ b/transport/lwm2m/pom.xml @@ -0,0 +1,163 @@ + + + 4.0.0 + + org.thingsboard + 3.2.0-SNAPSHOT + transport + + org.thingsboard.transport + lwm2m + jar + + Thingsboard LwM2m Transport Service + https://thingsboard.io + + + UTF-8 + ${basedir}/../.. + java + false + process-resources + package + tb-lwm2m-transport + false + ${project.build.directory}/windows + ThingsBoard LwM2m Transport Service + org.thingsboard.server.lwm2m.ThingsboardLwm2mTransportApplication + + + + + org.eclipse.leshan + leshan-server-cf + + + + org.eclipse.leshan + leshan-client-cf + + + + org.eclipse.leshan + leshan-server-redis + + + + org.springframework.boot + spring-boot-starter-test + test + + + junit + junit + test + + + org.mockito + mockito-all + test + + + org.eclipse.californium + californium-core + ${californium.version} + test-jar + test + + + org.eclipse.californium + element-connector + ${californium.version} + test-jar + test + + + + org.thingsboard.common.transport + lwm2m + + + org.thingsboard.common + queue + + + org.springframework.boot + spring-boot-starter-web + + + com.sun.winsw + winsw + bin + exe + provided + + + + + ${pkg.name}-${project.version} + + + ${project.basedir}/src/main/resources + + + + + org.apache.maven.plugins + maven-resources-plugin + + + org.apache.maven.plugins + maven-dependency-plugin + + + org.apache.maven.plugins + maven-jar-plugin + + + org.springframework.boot + spring-boot-maven-plugin + + + org.thingsboard + gradle-maven-plugin + + + org.apache.maven.plugins + maven-assembly-plugin + + + org.apache.maven.plugins + maven-install-plugin + + + + + + jenkins + Jenkins Repository + https://repo.jenkins-ci.org/releases + + false + + + + + diff --git a/transport/lwm2m/src/main/conf/logback.xml b/transport/lwm2m/src/main/conf/logback.xml new file mode 100644 index 0000000000..2f0980ffc9 --- /dev/null +++ b/transport/lwm2m/src/main/conf/logback.xml @@ -0,0 +1,45 @@ + + + + + + + ${pkg.logFolder}/${pkg.name}.log + + ${pkg.logFolder}/${pkg.name}.%d{yyyy-MM-dd}.%i.log + 100MB + 30 + 3GB + + + %d{ISO8601} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + + diff --git a/transport/lwm2m/src/main/conf/tb-lwm2m-transport.conf b/transport/lwm2m/src/main/conf/tb-lwm2m-transport.conf new file mode 100644 index 0000000000..3e239ef49b --- /dev/null +++ b/transport/lwm2m/src/main/conf/tb-lwm2m-transport.conf @@ -0,0 +1,23 @@ +# +# Copyright © 2016-2020 The Thingsboard Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +export JAVA_OPTS="$JAVA_OPTS -Xloggc:@pkg.logFolder@/gc.log -XX:+IgnoreUnrecognizedVMOptions -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDetails -XX:+PrintGCDateStamps" +export JAVA_OPTS="$JAVA_OPTS -XX:+PrintHeapAtGC -XX:+PrintTenuringDistribution -XX:+PrintGCApplicationStoppedTime -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10" +export JAVA_OPTS="$JAVA_OPTS -XX:GCLogFileSize=10M -XX:-UseBiasedLocking -XX:+UseTLAB -XX:+ResizeTLAB -XX:+PerfDisableSharedMem -XX:+UseCondCardMark" +export JAVA_OPTS="$JAVA_OPTS -XX:CMSWaitDuration=10000 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+CMSParallelInitialMarkEnabled" +export JAVA_OPTS="$JAVA_OPTS -XX:+CMSEdenChunksRecordAlways -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly" +export LOG_FILENAME=${pkg.name}.out +export LOADER_PATH=${pkg.installFolder}/conf diff --git a/transport/lwm2m/src/main/data/credentials/serverKeyStore.jks b/transport/lwm2m/src/main/data/credentials/serverKeyStore.jks new file mode 100644 index 0000000000000000000000000000000000000000..b5b6c9fa3c43118262f4c89b1ba319ef09b694d0 GIT binary patch literal 5716 zcma)qB?KfE>5`UM79>`>LrS_k1Z1TVP&x!r8kUe1VM&qhE)@w8Sh~AA zmi&2t^Sw25XYQRdbI#23ob%56ndklIKtidsv9WLo?xeTkAdo7uheNQdNgC*M#YWZ9C z8mtluT+B}uLJVIvNe`D=hTCtGC0g)8E|o0i_@b z<2`@}0RCrr0c-)*5SD+MU_nY;a=qs-?3o20i;F--p%6iF5g|cH$l(8gG9>n)%|!@z z`e~6E5#G>|r)1s2=wB!}k(R?oh60L<&#i@}v%BCdnBkr_vz`O3NxUnc)1(^JLQO`X zwV^mGbW}o64_&>?7Jy1|w}NaNo$EGd>HhAmm#N6Iv;_$&{cE?Bf|QKp0Gq#1JpbT$ z0IUHo|Mkj$0umJ!{@=3kibVTk`D@QL$9rwJ;V+EnGxGud0;;rg1_zNtQ=BRb2G*rk z1{WwmgJh<>=_BRh#8DPGxo=GRkn6h)S%ZV2IHFd4%w5-#$#p#yLTagW95m4%RqftYWhsK@*a6EN-rNBoq z+xux$aP8hQmpM^CsXSG5A!Q=@BOmD);TF?)bozM*K#acDrgh?^zPgoP6n-D@$nxW2P%Sa-k*uH}WFVH19iZtl0c zruOT#PpS#YiRmfbE6EO2WO!-9-Dn|>dN8?}^jKRKNU8zp05L%~o-&8Ib*McQ3BluF zNS`Xmx9fXAjca|+KA>!p;SK!rhu~b(a5}qnDj3**$$L%k<9X6nb_0xl%!F%5F*)% z<_%aH^l>CZbg$8fSNaY@62pK+K^dZ4)Wh}K@vU9T_-9Y)t3vFO`g#DU@-o7C7SFUn zcBV?R*Uj#}X0UWH7<0ZFCP8d6bA$IG%C=>5b_=m_^wX7267A#Nxci(>(hDVyJO0I* z7apu;$`x^!M`<-A+TnlVJ17L!9%Mu{sdB0SO)*^I&NMN6?z!U(Vza56>@uS-cP?9K z&0X!}gx7W?yAP^I(oI-Ew0CHJBQDSx962H{i&O1);>NWue0sx5Ds|ZG&l

t^Q*A zz2VM8H6^(VvE-u{#!Femel3CiPESCye(B!J&u9D^V`M zz$xC-NvsP}_BiwB(fc_NofT2Z4!P=CK_}{F-tF`>5R< z0@q0@4pHjD`*pRfU*h%?$!tnIh3B0J3qmQ`Dn&BL53X^0d@608MOLsDcM9d=aMI3? z&LfTUeC`$p(Zdv{5-u=YoU84x?)H6KWZVZG3UNV7B4pvsX9;3!>cU+`ik<~@5&gxw zP)H5EPJ?M zV5ndrZ&-|4@MGH=z1LgMU^-DgyUb>^MJFdH(OUDQ;Rp76!uOwMgPd`2Ij|SL4D{QX zNv<4r``x)@#4$Y4HSV_%$UCraFe1cRX!-T7+PbO%mD?ul9zd&eL)y3MYlZqolkSvA zVs(+}tI&#rm|v+Ky59JOxIL-U889}w@iZCp{W$@PSbZPV)y7DRV5qPab37rH>0fVR z>73o~$Vq)WFTQIU4Gz>IAiDW5j{h{BS7h3dSb+`nwu~%!os=)#jz;|9RY6v&Ov-!% zowQ)>2kbaR_&srS4&yINtZ7?%8jLw%K2vkmrcM5ChRpS{9LPhUUYsi+&sklq44Ztx zfU@kpDA$ElBu5H+Q8Bq`c(HDGSuMymJC3Bs2 z;OcTnnpOl*EoEQn!_S_Z!+@W|4sR}HDiH&(a3wP<&^~#yf+Y%&Ph0uH`j=bb!;!`B zu|UE#6H4#46F9fn3w)0g5FD>_WY%7bzI;n|_KUqEbxSYt&B13!QVL4!Rz+4c#kKln zrw&FqI6^#IN?kGf69&zHfkR+bO40DUpwDnw?F?Jl0=is00b+!^Q5zt+V42>mQ!cC? zMxhilcUgUlD;O-&h`883!Vr}J!IB;Wmd9y~d{(aqe* zCHp7^wEqkx3Qi`gwKsJsZQw`jPUwc?D*$C@DzSX-GlN7vkq+2mH+f23!2hrxn874? zv_2%k`|Fy!@ze*oZsun0oOpvMwCsGSPYI@1H=~z++p`+&)+Z=u49Z&V{?G}P*^yvh zfzihAOgY`kd0n{FFe{_CNOtH4NRG#|`K9=Sck{QyFSC@#!)n59hEm=y1#no-DAiR* zNcdH7nz}aNQzaA@IIh<{*A2*TbsryTC^TgoE)yJ7W$UUxDD{5CTOGQ~& zDLV(hxqS4(2nwSVMyef{4P>HUrWXu}fJlV>f;6mnVvz0?Je!G1_3(kNS z!!F9Nw#7@bc%&o0)qW5iywwP97rM@Cdgwu&JQ5ZttGVomP9TTv{&eF|9zv+=750Q+ zaQMcI3Cj$uyTUTJRw=yo@D8pDCpvo_N7vU0BJv1tibIEL!Xya7xT4y$YkaRh?eE@V zD=P2L%TwvqV*w11I%r~xfxvBo(n>8(#-xsIN!zX7{v0YJ3*{q&b-@Ajmt28&E4SB5 zC<|Dw2(6)}Smlj~u6$fy>;)@+WHD42K*s|SdQhda8Kica=@=^cZP37MLk$b_7_lKy zul6_}h(;l#UB!+FHhmV<#`exzS3^4N7_4t%l~?KM^*_8Uu1b1f3A18kblJt~bX0bn zl*|jd?m&Qe9+LXAc`kN#i3%{hRPThRWA0PDF}b~sAj535@g=6}_Gyk|z*B`PcXbRl zUm2A-fd=APyhAabdJV{q!O5E5#&H2q?aFvAKG#xAz5&PESE;lR3KNeoqG?P!)I7sC z{MeVDg#5CpGd*`;XIF!=zIaw)7$2XHOwP2aDyQ^gZuR@{7Npr=KV6;QDW?FjLnY_T zo5A6G8}kQ)Yb4j(rRB&n9_~|g_Dr+H>aeguZYU;(S6b=6JV_>)(6I0v1IHw zEf!ZOhm(~dI4o5w)JchDhGNo7IsXPPeg3LiCki1-Qhl)qMRQ#fcfO+38)tOk%8@lVP z#e=F)w3hNyvLaQj-I2dYX^$F{H{el=f~(SDy>c`akd)F`EiDX;slE`&ga_6wZ`O}; z`3P=I4C6~s@d7!-rH)kYUug$*%z-%>Hti*ijmBOY+Ss_3n2$gnv3p59$$+!rF9{7L z!0vQV71n|=5n=-<*NkkRx?jw!%|}KBkSU;Wt!2KJguTF=^|^=-T>zY$0Gx$Rjbp8U7(5g`R| z2lO0p>(ii*Mp5(y19wH!V0W1Fa&wi7Pola3$D<8O%Z{Mkc zsG#b2MeQ~i~8Cw1o4-og?YmTn?G$GzK*XrFzBRxh+d4=Xh}^Dk%GX%2M{jaD*g z9$Ul2u-m{L|LIo`K04$(oW3-cg9+)&XhamLHJr$E6yM~{z80M%rvz_ZZpBpl_>@=i zpo#4P9E;b9>D$%gy&B-xIKgYbi|apvWo8R(+wod=7gI9xc=> zOV4lE$|1n=%h|1c`dR7R5*nH-lDv! z%wu*K-U(bw4;U9q839}S4{lD(H!Ty);YQ#cC}L317bwMVQYktcD_q28q>y=u@5FCw zwfdC@Pkh%X%D;$^MlQKyOkq7qJzu9a;p6denhpE9ypwP^9~XFj_I}go5VwwP<&VAi z6VvqhC()mCel0ice({ob{W&Mx(z(v6Yuj(qYr=Jf>^b4(*|!`XGuXt5ta+=CTo=ko zN20d89d%B-n3OWC;YZ)Wv@zO`O)c)YjXTXSn>$U%T*{2CRj}tj!Z%ONCnANoryL{K zu!wwf+S<-{e*x?Yn$n8IORBZmGN@nNSR5kdJXxGYnj?z&SU+!zSF5e@Z?GE=3u5qh z(yQip6>xYtm`XFqQRbg=V=QY56+B}`E#u~yW6N#oXHpz##5TijonNIxW(#3j+EI)q z)M;$KGmXG*y8Bz@jyg`&@JiaIrh=$VLHZHdL@&CRxOyal4poNX`8h<1ILw&U#Y+~M zjbvrrHT{a$4)qJ4fvgx(Ieo`=0Yw{eCu_WMs}#U|SN6cq`jvzv-I2y|%vO_y?YeRS zXU!_oKf7)s4mRZ=D#0BS^xZ7yt%Oy;{WTY*y&)N`wvj&iSttKsx!>h@Z$4y3gb@|a z>BgTazbH_w%PGmF@tC_>4#v)cer&%K%VWWKNgX^5D;T8DXXfF_7Z<2TvGGsm~NuR zvqMUBqBr<=apnX6CWlEIoBl`{-G+xw;U+hrXUyG9`=POP$CIL^6v<}cI2q*9;`H|i zo!!sQ`zKz$_vheHlBMd*wCa}QdlB~_a~+Y`$aJa4S2F_Ph>ZgX0bjiX?uT zX&d7LyBF``a8Oe}?tf|bWg->|Bgj?lccoI@sTagXQy*CcSe5VYNo&xUe+#4RHl(uE zulHEdz}NfkcU&_3tj$;K0hgWj4PBLY-xq~OKhez2|4$C{SY1uUklvotUGZ?CGbDHDF;?N$gDt)i}$)dV=yaYEGI;coQc5P`K z`UPq^SJwI3ez~1(1y%Pbd#2>pD(fTBeCN;3fLQ)(N}K7vQvQ@z##LXlo+djeI!EiOu#@X2 z?(n#SKT8Rr3#}iSK&6^=o5Ecjl5bqHQ4mK?w0GBdcw7a$V8kDQ| qkcRm%4dLuH%rb{d=@zQVZ?hk0O%Ryaxn;x~P%wJagN=g~iTppw$f0Ne literal 0 HcmV?d00001 diff --git a/transport/lwm2m/src/main/data/models/10241.xml b/transport/lwm2m/src/main/data/models/10241.xml new file mode 100644 index 0000000000..228c8098e2 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10241.xml @@ -0,0 +1,98 @@ + + + + + + HostDeviceInfo + + 10241 + urn:oma:lwm2m:x:10241 + + + Multiple + Optional + + Host Device Manufacturer + R + Multiple + Mandatory + String + + + + + Host Device Model Number + R + Multiple + Mandatory + String + + + + + Host Device Unique ID + R + Multiple + Mandatory + String + + + + + Host Device Software Version + R + Multiple + Mandatory + String + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10242.xml b/transport/lwm2m/src/main/data/models/10242.xml new file mode 100644 index 0000000000..d9c8871f48 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10242.xml @@ -0,0 +1,647 @@ + + + + + 3-Phase Power Meter + + + + 10242 + urn:oma:lwm2m:x:10242 + 1.0 + 1.0 + Multiple + Optional + + + Manufacturer + R + Single + Optional + String + + + + + + + + Model Number + R + Single + Optional + String + + + + + + + + Serial Number + R + Single + Optional + String + + + + + + + + Description + R + Single + Optional + String + + + + + + + + Tension R + R + Single + Mandatory + Float + + V + + + + + + Current R + R + Single + Mandatory + Float + + A + + + + + + Active Power R + R + Single + Optional + Float + + kW + + + + + + Reactive Power R + R + Single + Optional + Float + + kvar + + + + + + Inductive Reactive Power R + R + Single + Optional + Float + + kvar + + + + + + Capacitive Reactive Power R + R + Single + Optional + Float + + kvar + + + + + + Apparent Power R + R + Single + Optional + Float + + kVA + + + + + + Power Factor R + R + Single + Optional + Float + -1..1 + + + + + + + THD-V R + R + Single + Optional + Float + + /100 + + + + + + THD-A R + R + Single + Optional + Float + + /100 + + + + + + Tension S + R + Single + Mandatory + Float + + V + + + + + + Current S + R + Single + Mandatory + Float + + A + + + + + + Active Power S + R + Single + Optional + Float + + kW + + + + + + Reactive Power S + R + Single + Optional + Float + + kvar + + + + + + Inductive Reactive Power S + R + Single + Optional + Float + + kvar + + + + + + Capacitive Reactive Power S + R + Single + Optional + Float + + kvar + + + + + + Apparent Power S + R + Single + Optional + Float + + kVA + + + + + + Power Factor S + R + Single + Optional + Float + -1..1 + + + + + + + THD-V S + R + Single + Optional + Float + + /100 + + + + + + THD-A S + R + Single + Optional + Float + + /100 + + + + + + Tension T + R + Single + Mandatory + Float + + V + + + + + + Current T + R + Single + Mandatory + Float + + A + + + + + + Active Power T + R + Single + Optional + Float + + kW + + + + + + Reactive Power T + R + Single + Optional + Float + + kvar + + + + + + Inductive Reactive Power T + R + Single + Optional + Float + + kvar + + + + + + Capacitive Reactive Power T + R + Single + Optional + Float + + kvar + + + + + + Apparent Power T + R + Single + Optional + Float + + kVA + + + + + + Power Factor T + R + Single + Optional + Float + -1..1 + + + + + + + THD-V T + R + Single + Optional + Float + + /100 + + + + + + THD-A T + R + Single + Optional + Float + + /100 + + + + + + 3-Phase Active Power + R + Single + Optional + Float + + kW + + + + + + 3-Phase Reactive Power + R + Single + Optional + Float + + kvar + + + + + + 3-Phase Inductive Reactive Power + R + Single + Optional + Float + + kvar + + + + + + 3-Phase Capacitive Reactive Power + R + Single + Optional + Float + + kvar + + + + + + 3-Phase Apparent Power + R + Single + Optional + Float + + kVA + + + + + + 3-Phase Power Factor + R + Single + Optional + Float + -1..1 + + + + + + + 3-Phase phi cosine + R + Single + Optional + Float + -1..1 + + + + + + + Active Energy + R + Single + Optional + Float + + kWh + + + + + + Reactive Energy + R + Single + Optional + Float + + kvarh + + + + + + Inductive Reactive Energy + R + Single + Optional + Float + + kvarh + + + + + + Capacitive Reactive Energy + R + Single + Optional + Float + + kvarh + + + + + + Apparent Energy + R + Single + Optional + Float + + kVAh + + + + + + Tension R-S + R + Single + Optional + Float + + V + + + + + + Tension S-T + R + Single + Optional + Float + + V + + + + + + Tension T-R + R + Single + Optional + Float + + V + + + + + + Frequency + R + Single + Optional + Float + + Hz + + + + + + Neutral Current + R + Single + Optional + Float + + A + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10243.xml b/transport/lwm2m/src/main/data/models/10243.xml new file mode 100644 index 0000000000..325c8cee0e --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10243.xml @@ -0,0 +1,251 @@ + + + + + Single-Phase Power Meter + + + + 10243 + urn:oma:lwm2m:x:10243 + 1.0 + 1.0 + Multiple + Optional + + + Manufacturer + R + Single + Optional + String + + + + + + + + Model Number + R + Single + Optional + String + + + + + + + + Serial Number + R + Single + Optional + String + + + + + + + + Description + R + Single + Optional + String + + + + + + + + Tension + R + Single + Mandatory + String + + V + + + + + + Current + R + Single + Mandatory + Float + + A + + + + + + Active Power + R + Single + Optional + Float + + kW + + + + + + Reactive Power + R + Single + Optional + Float + + kvar + + + + + + Inductive Reactive Power + R + Single + Optional + Float + + kvar + + + + + + Capacitive Reactive Power + R + Single + Optional + Float + + kvar + + + + + + Apparent Power + R + Single + Optional + Float + + kVA + + + + + + Power Factor + R + Single + Optional + Float + -1..1 + + + + + + + THD-V + R + Single + Optional + Float + + /100 + + + + + + THD-A + R + Single + Optional + Float + + /100 + + + + + + Active Energy + R + Single + Optional + Float + + kWh + + + + + + Reactive Energy + R + Single + Optional + Float + + kvarh + + + + + + Apparent Energy + R + Single + Optional + Float + + kVAh + + + + + + Frequency + R + Single + Optional + Float + + Hz + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10244.xml b/transport/lwm2m/src/main/data/models/10244.xml new file mode 100644 index 0000000000..320e74c5e4 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10244.xml @@ -0,0 +1,318 @@ + + + + VehicleControlUnit + + 10244 + urn:oma:lwm2m:x:10244 + Single + Optional + + Vehicle UI State + R + Single + Mandatory + Integer + 0..15 + + + + Vehicle Speed + R + Single + Mandatory + Integer + + km/h + + + Vehicle Shift Status + R + Single + Mandatory + Integer + 0..3 + + + + Vehicle AP Position + R + Single + Mandatory + Integer + 0..100 + /100 + + + Vehicle Power + R + Single + Optional + Float + + kW + + + Vehicle Drive Energy + R + Single + Optional + Float + + Wh + + + Vehicle Energy Consumption Efficiency + R + Single + Optional + Float + + Wh/km + + + Vehicle Estimated Mileage + R + Single + Optional + Integer + + km + + + Vehicle Charge Cable Status + R + Single + Mandatory + Boolean + + + + + Vehicle Charge Status + R + Single + Mandatory + Integer + 0..15 + + + + Vehicle Charge Voltage + R + Single + Mandatory + Float + + V + + + Vehicle Charge Current + R + Single + Mandatory + Float + + A + + + Vehicle Charge Remaining Time + R + Single + Mandatory + Integer + + min + + + Battery Pack Voltage + R + Single + Mandatory + Float + + V + + + Battery Pack Current + R + Single + Mandatory + Float + + A + + + Battery Pack Remaining Capacity + R + Single + Mandatory + Integer + + Ah + + + Battery Pack SOC + R + Single + Mandatory + Integer + 0..100 + /100 + + + Battery Pack SOH + R + Single + Mandatory + Integer + 0..100 + /100 + + + Battery Cell MinVolt + R + Single + Mandatory + Integer + + mV + + + Battery Cell MaxVolt + R + Single + Mandatory + Integer + + mV + + + Battery Module MinTemp + R + Single + Mandatory + Integer + + Cel + + + Battery Module MaxTemp + R + Single + Mandatory + Integer + + Cel + + + Battery Connection Status + R + Single + Mandatory + Boolean + + + + + + MCU Voltage + R + Single + Mandatory + Integer + + V + + + MCU Temperature + R + Single + Mandatory + Integer + + Cel + + + Motor Speed + R + Single + Mandatory + Integer + + 1/min + + + Motor Temperature + R + Single + Mandatory + Integer + + Cel + + + Motor OT Warning + R + Single + Optional + Boolean + + + + + MCU OT Warning + R + Single + Optional + Boolean + + + + + Battery Pack OT Warning + R + Single + Optional + Boolean + + + + + MCU fault + R + Single + Optional + Boolean + + + + + Motor Error + R + Single + Optional + Boolean + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10245.xml b/transport/lwm2m/src/main/data/models/10245.xml new file mode 100644 index 0000000000..3bb5219949 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10245.xml @@ -0,0 +1,203 @@ + + + + + Relay Management + This LWM2M Object provides a range of eNB related measurements and parameters of which several are changeable. Furthermore, it includes Resources to enable/disable the eNB. + 10245 + urn:oma:lwm2m:x:10245 + + + Single + Optional + + + eNB Availability + R + Single + Mandatory + Boolean + AVAILABLE; UNAVAILABLE + + This field indicates to the CCC whether or not the eNB of the CrowdBox is available for activation: AVAILABLE = TRUE; UNAVAILABLE = FALSE This is set by the CrowdBox itself using an algorithm specific to the use case and based on parameters known to the CrowdBox which may not necessarily be signalled to the network. In the absence of a more specific algorithm, this parameter should be set to AVAILABLE, unless a fault is detected which would prevent activation of the eNB, in which case it should be set to UNAVAILABLE. + + + GPS Status + R + Single + Mandatory + Boolean + UNSYNCHRONISED; SYNCHRONISED + + States whether the CrowdBox GPS receiver is synchronised to GPS time or not: UNSYCHRONISED = FALSE; SYNCHRONISED = TRUE If more than one GPS receiver is used by the CrowdBox, then SYNCHRONISED should be reported only if all receivers are synchronised. + + + Orientation + R + Single + Optional + Integer + -180..180 + deg + Orientation of CrowdBox with respect to magnetic north. The reference orientation of the CrowdBox shall be the pointing direction of the eNB antenna(s) or, in the case of an omni-directional CrowdBox antenna, as defined in the accompanying product documentation. + + + eNB EARFCN + RW + Single + Mandatory + Integer + 0..65535 + + EARFCN currently used by the eNB. Highest valid value in 3GPP is currently 46589. If the requested EARFCN is not supported by the eNB, the response should be "Bad Request". The CrowdBox shall only apply a change of this resource upon execution of the “Enable eNB” command. + + + eNB Bandwidth + RW + Single + Mandatory + Integer + 5, 10, 15, 20 + + Bandwidth of the currently used eNB carrier. If the requested bandwidth is not supported by the eNB, the response should be "Bad Request". The CrowdBox shall only apply a change of this resource upon execution of the “Enable eNB” command. + + + Backhaul Primary EARFCN + RW + Single + Mandatory + Integer + 0..65535 + + EARFCN of primary cell used for the backhaul. If the requested EARFCN is not supported by the CrowdBox UE, the response should be "Bad Request". The CrowdBox shall only apply a change of this resource upon execution of the “Enable eNB” command. + + + Backhaul Secondary EARFCN + RW + Multiple + Mandatory + Integer + 0..65535 + + EARFCN of any secondary cells used for the backhaul, in the event that carrier aggregation is being used. If the requested EARFCN is not supported by the CrowdBox UE, the response should be "Bad Request". The CrowdBox shall only apply a change of this resource upon execution of the “Enable eNB” command. + + + Cumulative Measurement Window + RW + Single + Mandatory + Integer + 0..65535 + s + The current measurement interval over which cumulative statistics are collected for the following resources: Cumulative Number of Unique Users, Cumulative Downlink Throughput per Connected User, Cumulative Uplink Throughput per Connected User. Note that this measurement period is a sliding window rather than a granularity period. Measurements should never be reset, but rather old measurements should be removed from the cumulative total as they fall outside of the window. A value of 0 shall be interpreted as meaning only the current value should be reported. A value of 65535 shall be interpreted as an infinite window size (i.e. old measurements are never discarded). + + + eNB ECI + R + Single + Mandatory + Integer + 0..2^28-1 + + A 28 bit E-UTRAN Cell Identifier (ECI) + + + eNB Status + RW + Single + Mandatory + Boolean + + + This resource indicates the current status of the eNB and can be used by the CCC to change the state from enabled to disabled. TRUE = eNB enabled FALSE = eNB disabled + + + Enable eNB + E + Single + Mandatory + + + + Enables the eNB. In addition the CrowdBox shall also update its configuration to reflect the current state of other relevant parameters. This might require a reboot. + + + eNB Maximum Power + RW + Single + Mandatory + Integer + 0..63 + dBm + Maximum power for the eNB measured as the sum of input powers to all antenna connectors. The maximum power per antenna port is equal to the maximum eNB power divided by the number of antenna ports. If the requested power is above or below the maximum or minimum power levels of the eNB, then the power level should be set to the maximum or minimum respectively. The CrowdBox shall only apply a change of this resource upon execution of the “Enable eNB” command. + + + Backhaul Primary q-OffsetFreq + RW + Single + Mandatory + Integer + -24..24 + dB + q-OffsetFreq parameter for the backhaul primary EARFCN in SIB5 of the CrowdBox eNB BCCH. See TS 36.331 for details. Range: dB-24; dB-22 .. dB24 The CrowdBox shall only apply a change of this resource upon execution of the “Enable eNB” command. + + + Backhaul Secondary q-OffsetFreq + RW + Multiple + Mandatory + Integer + -24..24 + dB + q-OffsetFreq parameter for the backhaul secondary EARFCN in SIB5 of the CrowdBox eNB BCCH. See TS 36.331 for details Range: dB-24; dB-22 .. dB24 The CrowdBox shall only apply a change of this resource upon execution of the “Enable eNB” command. + + + Neighbour CrowdBox EARFCN + RW + Multiple + Mandatory + Integer + 0..66635 + + EARFCN of a neighbour CrowdBox. Each instance of this resource relates to the same instance of resource ID 15. + + + Neighbour CrowdBox q-OffsetFreq + RW + Multiple + Mandatory + Integer + -24..24 + dB + q-OffsetFreq parameter of the Neighbour CrowdBox EARFCN in SIB5 of the Neighbour CrowdBox eNB BCCH. See TS 36.331 for details Range: dB-24; dB-22 .. dB24 Each instance of this resource relates to the same instance of resource ID 14. The CrowdBox shall only apply a change of this resource upon execution of the “Enable eNB” command. + + + Serving Macro eNB cellIndividualOffset + RW + Single + Mandatory + Integer + -24..24 + dB + Specifies the value of the cellIndividualOffset parameter applicable to the CrowdBox macro serving cell that is to be signalled to connected UEs in their measurement configuration information . See TS 36.331 for details. The CrowdBox shall only apply a change of this resource upon execution of the “Enable eNB” command. + + + + + diff --git a/transport/lwm2m/src/main/data/models/10246.xml b/transport/lwm2m/src/main/data/models/10246.xml new file mode 100644 index 0000000000..6e2965817c --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10246.xml @@ -0,0 +1,93 @@ + + + + + CrowdBox Measurements + This LWM2M Object provides CrowdBox-related measurements such as serving cell parameters, backhaul timing advance, and neighbour cell reports. + 10246 + urn:oma:lwm2m:x:10246 + + + Single + Optional + + + Serving Cell ID + R + Single + Mandatory + Integer + 0..2^32-1 + + Serving cell ID as specified by the cellIdentity field broadcast in SIB1 of the serving cell (see TS 36.331). + + + Serving Cell RSRP + R + Single + Mandatory + Integer + 0..97 + + Serving cell RSRP, as defined in TS 36.133, Section 9.1.4. Range: RSRP_00; RSRP_01 .. RSRP_97 + + + Serving Cell RSRQ + R + Single + Mandatory + Integer + -30..46 + + Serving cell RSRQ, as defined in TS 36.133, Section 9.1.7. Range: RSRQ_-30; RSRQ_-29 .. RSRQ_46 + + + Serving Cell SINR + R + Single + Mandatory + Integer + -10..30 + dB + SINR of serving cell as estimated by the CrowdBox. Note that this is a proprietary measurement dependent on the UE chipset manufacturer. The UE chipset used should be stated in the accompanying product documentation. + + + Cumulative Backhaul Timing Advance + R + Single + Optional + Integer + 0..65535 + + The cumulative timing advance signalled by the current serving cell to the CrowdBox. This is the sum of the initial timing advance signalled in the MAC payload of the Random Access Response (11 bits, 0 .. 1282) and subsequent adjustments signalled in the MAC PDU of DL-SCH transmissions (6 bits, -31 .. 32). See TS 36.321 for details. + + + Neighbour Cell Report + R + Multiple + Mandatory + Objlnk + + + A link to the "Neighbour Cell Report" object for each neighbour cell of the CrowdBox. + + + + + diff --git a/transport/lwm2m/src/main/data/models/10247.xml b/transport/lwm2m/src/main/data/models/10247.xml new file mode 100644 index 0000000000..81dd8486eb --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10247.xml @@ -0,0 +1,83 @@ + + + + + Neighbour Cell Report + This LWM2M Object provides the neighbour cell report. The CrowdBox Measurements Object and the Connected UE Report Object have both Objlnk Resources pointing to this Object. + 10247 + urn:oma:lwm2m:x:10247 + + + Multiple + Optional + + + Neighbour PCI + R + Single + Mandatory + Integer + 0..503 + + Physical Cell ID of neighbouring LTE cell, as defined in TS 36.211 + + + Neighbour Cell ID + R + Single + Optional + Integer + 0..2^32-1 + + Neighbour cell ID as specified by the cellIdentity field broadcast in SIB1 of the neighbour cell (see TS 36.331). + + + Neighbour Cell Rank + R + Single + Mandatory + Integer + 0..255 + + Current neighbour cell rank. Neighbour cells should be ordered (ranked) by the CrowdBox according to neighbour cell RSRP, with a higher RSRP corresponding to a lower index. Hence the neighbouring cell with the highest RSRP should be neighbour cell 0, the second neighbour cell 1, and so on. + + + Neighbour Cell RSRP + R + Single + Mandatory + Integer + 0..97 + + Neighbour cell RSRP, as defined in TS 36.133, Section 9.1.4. Range: RSRP_00; RSRP_01 .. RSRP_97 + + + Neighbour Cell RSRQ + R + Single + Mandatory + Integer + -30..46 + + Neighbour cell RSRQ, as defined in TS 36.133, Section 9.1.7. Range: RSRQ_-30; RSRQ_-29 .. RSRQ_46 + + + + + diff --git a/transport/lwm2m/src/main/data/models/10248.xml b/transport/lwm2m/src/main/data/models/10248.xml new file mode 100644 index 0000000000..aaef046e5d --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10248.xml @@ -0,0 +1,63 @@ + + + + + Connected UE Measurements + This LWM2M Object provides a range of measurements of connected UEs and provides an Object link to the Connected UE report. + 10248 + urn:oma:lwm2m:x:10248 + + + Single + Optional + + + Number of Connected Users + R + Single + Mandatory + Integer + 0..255 + + The number of different UEs currently connected to the eNB (i.e. in RRC_CONNECTED state). + + + Cumulative Number of Unique Users + R + Single + Mandatory + Integer + 0..65535 + + The number of different UEs that have connected to the eNB over the immediately preceding period specified by the "Cumulative Measurement Window" field. + + + Connected UE Report + R + Multiple + Mandatory + Objlnk + + + Provides an Object link to the Connected UE Report which provides a range of information related to the connected UEs. + + + + + diff --git a/transport/lwm2m/src/main/data/models/10249.xml b/transport/lwm2m/src/main/data/models/10249.xml new file mode 100644 index 0000000000..d89b8df658 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10249.xml @@ -0,0 +1,123 @@ + + + + + Connected UE Report + This LWM2M Object provides a range of information related to the connected UEs. + 10249 + urn:oma:lwm2m:x:10249 + + + Multiple + Optional + + + Connected User MMEC + R + Single + Mandatory + Integer + 0..255 + + MMEC signalled by the UE to the eNB in the RRCConnectionRequest message (see TS 36.331). + + + Connected User M-TMSI + R + Single + Mandatory + Integer + 0..2^32-1 + + M-TMSI signalled by the UE to the eNB in the RRCConnectionRequest message (see TS 36.331). + + + Serving Cell (CrowdBox) eNB RSRP + R + Single + Mandatory + Integer + 0..97 + + The RSRP of the CrowdBox eNB, as defined in TS 36.133, Section 9.1.4. Range: RSRP_00; RSRP_01 .. RSRP_97 + + + Serving Cell (CrowdBox) eNB RSRQ + R + Single + Mandatory + Integer + -30..46 + + The RSRQ of the CrowdBox eNB, as defined in TS 36.133, Section 9.1.7. Range: RSRQ_-30; RSRQ_-29 .. RSRQ_46 + + + Cumulative Timing Advance per Connected User + R + Single + Optional + Integer + 0..65535 + + The cumulative timing advance signalled by the eNB to each currently connected UE. This is the sum of the initial timing advance signalled in the MAC payload of the Random Access Response (11 bits, 0 .. 1282) and subsequent adjustments signalled in the MAC PDU of DL-SCH transmissions (6 bits, -31 .. 32). See TS 36.321 for details. + + + Last downlink CQI report per Connected User + R + Single + Mandatory + Integer + 0..255 + + The last downlink wideband CQI reported by a connected user the eNB. The CQI format is defined in Table 7.2.3-1 of TS 36.213. + + + Cumulative Downlink Throughput per Connected User + R + Single + Mandatory + Integer + 0..2^32-1 + B + The total number of MAC bytes sent to the connected user over the immediately preceding period specified by the "Cumulative Measurement Window" field. + + + Cumulative Uplink Throughput per Connected User + R + Single + Mandatory + Integer + 0..2^32-1 + B + The total number of MAC bytes received from the connected user over the immediately preceding period specified by the "Cumulative Measurement Window" field. + + + Neighbour Cell Report + R + Multiple + Mandatory + Objlnk + + + A link to the "Neighbour Cell Report" object for each neighbour cell reported to the CrowdBox by the connected UE + + + + + diff --git a/transport/lwm2m/src/main/data/models/10250.xml b/transport/lwm2m/src/main/data/models/10250.xml new file mode 100644 index 0000000000..871ede5741 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10250.xml @@ -0,0 +1,87 @@ + + + + + + App Data Container + + 10250 + urn:oma:lwm2m:x:10250 + 1.0 + 1.0 + Single + Optional + + + UL data + R + Single + Mandatory + Opaque + + + + + + + + DL data + W + Single + Mandatory + Opaque + + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10251.xml b/transport/lwm2m/src/main/data/models/10251.xml new file mode 100644 index 0000000000..6b32032097 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10251.xml @@ -0,0 +1,83 @@ + + + + + AT Command + + 10251 + urn:oma:lwm2m:x:10251 + 1.0 + 1.0 + Multiple + Optional + + + Command + RW + Single + Mandatory + String + + + + + + Response + R + Multiple + Mandatory + String + + + + + + Status + R + Multiple + Mandatory + String + + + + + + Timeout + RW + Single + Optional + Integer + + + + + + Run + E + Single + Mandatory + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10252.xml b/transport/lwm2m/src/main/data/models/10252.xml new file mode 100644 index 0000000000..f6ec9bf3bd --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10252.xml @@ -0,0 +1,168 @@ + + + + Manifest + + 10252 + urn:oma:lwm2m:x:10252 + 1.0 + 1.0 + Single + Optional + + + Manifest + W + Single + Mandatory + Opaque + + + + + + + + State + R + Single + Mandatory + Integer + 0..8 + + + + + + Manifest Result + R + Single + Mandatory + Integer + 0..19 + + + + + + Payload Result + R + Single + Mandatory + Opaque + + + + + + + + Asset Hash + R + Single + Mandatory + Opaque + + + + + + + + Manifest version + R + Single + Mandatory + Integer + + + + + + + + Asset Installation Progress + R + Single + Mandatory + Integer + + + + + + + + Campaign Id + RW + Single + Mandatory + String + + + + + + + + Manual Trigger + E + Single + Mandatory + + + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10253.xml b/transport/lwm2m/src/main/data/models/10253.xml new file mode 100644 index 0000000000..5d06a21ae4 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10253.xml @@ -0,0 +1,57 @@ + + + + + Confidential Data + + 10253 + urn:oma:lwm2m:x:10253 + 1.0 + 1.0 + Single + Optional + + + Public Key + RW + Single + Mandatory + Opaque + + + + + + + + Application Data + R + Single + Mandatory + Opaque + + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10254.xml b/transport/lwm2m/src/main/data/models/10254.xml new file mode 100644 index 0000000000..805d77df58 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10254.xml @@ -0,0 +1,123 @@ + + + + + Current Loop Input + + 10254 + urn:oma:lwm2m:x:10254:1.0 + 1.0 + 1.0 + Multiple + Optional + + + Current Loop Input Current Value + R + Single + Mandatory + Float + 0; 3.8-20.5 + mA + + + + Min Measured Value + R + Single + Optional + Float + + + + + + Max Measured Value + R + Single + Optional + Float + + + + + + Min Range Value + R + Single + Optional + Float + + + + + + Max Range Value + R + Single + Optional + Float + + + + + + Reset Min and Max Measured Values + E + Single + Optional + + + + + + + Sensor Units + R + Single + Optional + String + + + + + + Application Type + RW + Single + Optional + String + + + + + + Current Calibration + RW + Single + Optional + Float + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10255.xml b/transport/lwm2m/src/main/data/models/10255.xml new file mode 100644 index 0000000000..bb1b791046 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10255.xml @@ -0,0 +1,104 @@ + + + + Device Metadata + + 10255 + urn:oma:lwm2m:x:10255 + 1.0 + 1.0 + Single + Optional + + + Protocol supported + R + Single + Mandatory + Integer + + + + + + + + Bootloader hash + R + Single + Mandatory + Opaque + + + + + + + + OEM bootloader hash + R + Single + Mandatory + Opaque + + + + + + + + Vendor + R + Single + Mandatory + String + + + + + + + + Class + R + Single + Mandatory + String + + + + + + + + Device + R + Single + Mandatory + String + + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10256.xml b/transport/lwm2m/src/main/data/models/10256.xml new file mode 100644 index 0000000000..cf3141133a --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10256.xml @@ -0,0 +1,134 @@ + + + + + ECID-Signal Measurement Information + + 10256 + urn:oma:lwm2m:x:10256 + 1.0 + 1.0 + Multiple + Optional + + + physCellId + R + Single + Mandatory + Integer + + + + + + + + ECGI + R + Single + Optional + Integer + + + + + + + + arfcnEUTRA + R + Single + Mandatory + Integer + + + + + + + + rsrp-Result + R + Single + Mandatory + Integer + + + + + + + + rsrq-Result + R + Single + Optional + Integer + + + + + + + + ue-RxTxTimeDiff + R + Single + Optional + Integer + + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10257.xml b/transport/lwm2m/src/main/data/models/10257.xml new file mode 100644 index 0000000000..adbbb51222 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10257.xml @@ -0,0 +1,292 @@ + + + + + Heat / Cooling meter + + 10257 + urn:oma:lwm2m:x:10257 + 1.0 + 1.0 + Multiple + Optional + + + Manufacturer + R + Single + Optional + String + + + + + + Model Number + R + Single + Optional + String + + + + + + Serial Number + R + Single + Optional + String + + + + + + Description + R + Single + Optional + String + + + + + + Error code + R + Multiple + Optional + Integer + + + + + + + Instantaneous active power + R + Single + Optional + Float + + W + + + + Max Measured active power + R + Multiple + Mandatory + Float + + W + + + + Cumulative active power + R + Single + Optional + Float + + Wh + + + + Flow temperature + R + Single + Optional + Float + + Cel + + + + Max Measured flow temperature + R + Single + Optional + Float + + Cel + + + + Return temperature + R + Single + Optional + Float + + Cel + + + + Max Measured return temperature + R + Single + Optional + Float + + Cel + + + + Temperature difference + R + Single + Optional + Float + + K + + + + Flow rate + R + Single + Optional + Float + + m3/s + + + + Max Measured flow + R + Single + Optional + Float + + m3/s + + + + Flow volume + R + Single + Optional + Float + + m3 + + + + Return volume + R + Single + Optional + Float + + m3 + + + + Current Time + RW + Single + Optional + Time + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10258.xml b/transport/lwm2m/src/main/data/models/10258.xml new file mode 100644 index 0000000000..3989a7dcb9 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10258.xml @@ -0,0 +1,93 @@ + + + + + Current Loop Output + + 10258 + urn:oma:lwm2m:x:10258 + 1.0 + 1.0 + Multiple + Optional + + + Current Loop Output Current Value + RW + Single + Mandatory + Float + 3.8-20.5 + mA + + + + Min Range Value + R + Single + Optional + Float + + + + + + Max Range Value + R + Single + Optional + Float + + + + + + Sensor Units + R + Single + Optional + String + + + + + + Application Type + RW + Single + Optional + String + + + + + + Current Calibration + RW + Single + Optional + Float + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10259.xml b/transport/lwm2m/src/main/data/models/10259.xml new file mode 100644 index 0000000000..48472c0b51 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10259.xml @@ -0,0 +1,100 @@ + + + + + System Log + + 10259 + urn:oma:lwm2m:x:10259 + 1.0 + 1.0 + Multiple + Optional + + + Name + R + Single + Mandatory + String + + + + + + + + Read All + R + Single + Mandatory + String + + + + + + + + Read + R + Single + Optional + String + + + + + + + + Enabled + RW + Single + Optional + Boolean + + + + + + + + Capture Level + RW + Single + Optional + Integer + + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10260-2_0.xml b/transport/lwm2m/src/main/data/models/10260-2_0.xml new file mode 100644 index 0000000000..371248ddb8 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10260-2_0.xml @@ -0,0 +1,81 @@ + + + + + RDB + + 10260 + urn:oma:lwm2m:x:10260:2.0 + 1.0 + 2.0 + Multiple + Optional + + + Key + RW + Single + Mandatory + String + + + + + + + + Value + RW + Single + Optional + String + + + + + + + + Exists + RW + Single + Optional + Boolean + + + + + + + + Persistent + RW + Single + Optional + Boolean + + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10262.xml b/transport/lwm2m/src/main/data/models/10262.xml new file mode 100644 index 0000000000..a4ed354dfe --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10262.xml @@ -0,0 +1,72 @@ + + + + + Interval Data Delivery + + 10262 + urn:oma:lwm2m:x:10262 + Multiple + Optional + + + Name + RW + Single + Mandatory + String + + + + + + Interval Data Links + RW + Multiple + Mandatory + Objlnk + + + + + + Latest Payload + R + Multiple + Mandatory + Opaque + + + + + + Schedule + RW + Single + Optional + Objlnk + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10263.xml b/transport/lwm2m/src/main/data/models/10263.xml new file mode 100644 index 0000000000..72a41a01e0 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10263.xml @@ -0,0 +1,75 @@ + + + + + Event Data Delivery + + 10263 + urn:oma:lwm2m:x:10263 + Multiple + Optional + + + Name + RW + Single + Mandatory + String + + + + + + Event Data Links + RW + Multiple + Mandatory + Objlnk + + + + + + Latest Eventlog + R + Multiple + Mandatory + Opaque + + + + + + Schedule + RW + Single + Mandatory + Objlnk + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10264.xml b/transport/lwm2m/src/main/data/models/10264.xml new file mode 100644 index 0000000000..76b6daa42d --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10264.xml @@ -0,0 +1,102 @@ + + + + + Delivery Schedule + + 10264 + urn:oma:lwm2m:x:10264 + Multiple + Optional + + + Schedule Start Time + RW + Single + Mandatory + Integer + + + + + + Schedule UTC Offset + RW + Single + Mandatory + String + + + + + + Delivery Frequency + RW + Single + Mandatory + Integer + + + + + + Randomised Delivery Window + RW + Single + Optional + Integer + + + + + + Number of Retries + RW + Single + Optional + Integer + + + + + + Retry Period + RW + Single + Optional + Integer + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10265.xml b/transport/lwm2m/src/main/data/models/10265.xml new file mode 100644 index 0000000000..43d852e301 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10265.xml @@ -0,0 +1,121 @@ + + + + + Leakage Detection Configuration + + 10265 + urn:oma:lwm2m:x:10265 + Single + Optional + + + Sample Times + RW + Multiple + Mandatory + Integer + + + + + + Sample UTC Offset + RW + Single + Optional + String + + + + + + Detection Mode + RW + Single + Mandatory + Integer + 0..3 + + + + + Top Frequency Count + RW + Single + Optional + Integer + + + + + + Frequency Thresholds + RW + Multiple + Optional + Integer + 0..999 + + + + + Frequency Values + R + Multiple + Optional + Integer + + + + + + Firmware Version + R + Single + Mandatory + String + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10266.xml b/transport/lwm2m/src/main/data/models/10266.xml new file mode 100644 index 0000000000..916586f04d --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10266.xml @@ -0,0 +1,229 @@ + + + + + Water Flow Readings + + 10266 + urn:oma:lwm2m:x:10266 + Multiple + Optional + + + Interval Period + R + Single + Mandatory + Integer + 1..864000 + s + + + + Interval Start Offset + R + Single + Optional + Integer + 0..86399 + s + + + + Interval UTC Offset + R + Single + Optional + String + + + + + + Interval Collection Start Time + R + Single + Mandatory + Time + + + + + + Oldest Recorded Interval + R + Single + Mandatory + Time + + + + + + Last Delivered Interval + RW + Single + Optional + Time + + + + + + Latest Recorded Interval + R + Single + Mandatory + Time + + + + + + Interval Delivery Midnight Aligned + RW + Single + Mandatory + Boolean + + + + + + Interval Historical Read + E + Single + Optional + + + + + + + Interval Historical Read Payload + R + Single + Optional + Opaque + + + + + + Interval Change Configuration + E + Single + Optional + + + + + + + Start + E + Single + Optional + + + + + + + Stop + E + Single + Optional + + + + + + + Status + R + Single + Optional + Integer + + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10267.xml b/transport/lwm2m/src/main/data/models/10267.xml new file mode 100644 index 0000000000..db7989ba57 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10267.xml @@ -0,0 +1,229 @@ + + + + + Daily Maximum Flow Rate Readings + + 10267 + urn:oma:lwm2m:x:10267 + Multiple + Optional + + + Interval Period + R + Single + Mandatory + Integer + 1..864000 + s + + + + Interval Start Offset + R + Single + Optional + Integer + 0..86399 + s + + + + Interval UTC Offset + R + Single + Optional + String + + + + + + Interval Collection Start Time + R + Single + Mandatory + Time + + + + + + Oldest Recorded Interval + R + Single + Mandatory + Time + + + + + + Last Delivered Interval + RW + Single + Optional + Time + + + + + + Latest Recorded Interval + R + Single + Mandatory + Time + + + + + + Interval Delivery Midnight Aligned + RW + Single + Mandatory + Boolean + + + + + + Interval Historical Read + E + Single + Optional + + + + + + + Interval Historical Read Payload + R + Single + Optional + Opaque + + + + + + Interval Change Configuration + E + Single + Optional + + + + + + + Start + E + Single + Optional + + + + + + + Stop + E + Single + Optional + + + + + + + Status + R + Single + Optional + Integer + + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10268.xml b/transport/lwm2m/src/main/data/models/10268.xml new file mode 100644 index 0000000000..7042a7d511 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10268.xml @@ -0,0 +1,229 @@ + + + + + Temperature Readings + + 10268 + urn:oma:lwm2m:x:10268 + Multiple + Optional + + + Interval Period + R + Single + Mandatory + Integer + 1..864000 + s + + + + Interval Start Offset + R + Single + Optional + Integer + 0..86399 + s + + + + Interval UTC Offset + R + Single + Optional + String + + + + + + Interval Collection Start Time + R + Single + Mandatory + Time + + + + + + Oldest Recorded Interval + R + Single + Mandatory + Time + + + + + + Last Delivered Interval + RW + Single + Optional + Time + + + + + + Latest Recorded Interval + R + Single + Mandatory + Time + + + + + + Interval Delivery Midnight Aligned + RW + Single + Mandatory + Boolean + + + + + + Interval Historical Read + E + Single + Optional + + + + + + + Interval Historical Read Payload + R + Single + Optional + Opaque + + + + + + Interval Change Configuration + E + Single + Optional + + + + + + + Start + E + Single + Optional + + + + + + + Stop + E + Single + Optional + + + + + + + Status + R + Single + Optional + Integer + + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10269.xml b/transport/lwm2m/src/main/data/models/10269.xml new file mode 100644 index 0000000000..ad8037184f --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10269.xml @@ -0,0 +1,229 @@ + + + + + Pressure Readings + + 10269 + urn:oma:lwm2m:x:10269 + Multiple + Optional + + + Interval Period + R + Single + Mandatory + Integer + 1..864000 + s + + + + Interval Start Offset + R + Single + Optional + Integer + 0..86399 + s + + + + Interval UTC Offset + R + Single + Optional + String + + + + + + Interval Collection Start Time + R + Single + Mandatory + Time + + + + + + Oldest Recorded Interval + R + Single + Mandatory + Time + + + + + + Last Delivered Interval + RW + Single + Optional + Time + + + + + + Latest Recorded Interval + R + Single + Mandatory + Time + + + + + + Interval Delivery Midnight Aligned + RW + Single + Mandatory + Boolean + + + + + + Interval Historical Read + E + Single + Optional + + + + + + + Interval Historical Read Payload + R + Single + Optional + Opaque + + + + + + Interval Change Configuration + E + Single + Optional + + + + + + + Start + E + Single + Optional + + + + + + + Stop + E + Single + Optional + + + + + + + Status + R + Single + Optional + Integer + + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10270.xml b/transport/lwm2m/src/main/data/models/10270.xml new file mode 100644 index 0000000000..00c3a889a2 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10270.xml @@ -0,0 +1,229 @@ + + + + + Battery Level Readings + + 10270 + urn:oma:lwm2m:x:10270 + Multiple + Optional + + + Interval Period + R + Single + Mandatory + Integer + 1..864000 + s + + + + Interval Start Offset + R + Single + Optional + Integer + 0..86399 + s + + + + Interval UTC Offset + R + Single + Optional + String + + + + + + Interval Collection Start Time + R + Single + Mandatory + Time + + + + + + Oldest Recorded Interval + R + Single + Mandatory + Time + + + + + + Last Delivered Interval + RW + Single + Optional + Time + + + + + + Latest Recorded Interval + R + Single + Mandatory + Time + + + + + + Interval Delivery Midnight Aligned + RW + Single + Mandatory + Boolean + + + + + + Interval Historical Read + E + Single + Optional + + + + + + + Interval Historical Read Payload + R + Single + Optional + Opaque + + + + + + Interval Change Configuration + E + Single + Optional + + + + + + + Start + E + Single + Optional + + + + + + + Stop + E + Single + Optional + + + + + + + Status + R + Single + Optional + Integer + + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10271.xml b/transport/lwm2m/src/main/data/models/10271.xml new file mode 100644 index 0000000000..105a39b312 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10271.xml @@ -0,0 +1,229 @@ + + + + + Communications Activity Time Readings + + 10271 + urn:oma:lwm2m:x:10271 + Multiple + Optional + + + Interval Period + R + Single + Mandatory + Integer + 1..864000 + s + + + + Interval Start Offset + R + Single + Optional + Integer + 0..86399 + s + + + + Interval UTC Offset + R + Single + Optional + String + + + + + + Interval Collection Start Time + R + Single + Mandatory + Time + + + + + + Oldest Recorded Interval + R + Single + Mandatory + Time + + + + + + Last Delivered Interval + RW + Single + Optional + Time + + + + + + Latest Recorded Interval + R + Single + Mandatory + Time + + + + + + Interval Delivery Midnight Aligned + RW + Single + Mandatory + Boolean + + + + + + Interval Historical Read + E + Single + Optional + + + + + + + Interval Historical Read Payload + R + Single + Optional + Opaque + + + + + + Interval Change Configuration + E + Single + Optional + + + + + + + Start + E + Single + Optional + + + + + + + Stop + E + Single + Optional + + + + + + + Status + R + Single + Optional + Integer + + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10272.xml b/transport/lwm2m/src/main/data/models/10272.xml new file mode 100644 index 0000000000..c93162a834 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10272.xml @@ -0,0 +1,215 @@ + + + + + Water Meter Customer Leakage Alarm + + 10272 + urn:oma:lwm2m:x:10272 + Multiple + Optional + + + Event Type + RW + Single + Mandatory + Integer + + + + + + Alarm Realtime + RW + Single + Mandatory + Boolean + + + + + + Alarm State + R + Single + Optional + Boolean + + + + + + Alarm Set Threshold + RW + Single + Optional + Float + + + + + + Alarm Set Operator + RW + Single + Optional + Integer + + + + + + Alarm Clear Threshold + RW + Single + Optional + Float + + + + + + Alarm Clear Operator + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Count + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Period + RW + Single + Optional + Integer + 1..864000 + s + + + + Latest Delivered Event Time + RW + Single + Optional + Time + + + + + + Latest Recorded Event Time + R + Single + Mandatory + Time + + + + + + Alarm Clear + E + Single + Optional + + + + + + + Alarm Auto Clear + RW + Single + Optional + Boolean + + + + + + Event Code + R + Single + Mandatory + Integer + 100..255 + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10273.xml b/transport/lwm2m/src/main/data/models/10273.xml new file mode 100644 index 0000000000..b39695f109 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10273.xml @@ -0,0 +1,215 @@ + + + + + Water Meter Reverse Flow Alarm + + 10273 + urn:oma:lwm2m:x:10273 + Multiple + Optional + + + Event Type + RW + Single + Mandatory + Integer + + + + + + Alarm Realtime + RW + Single + Mandatory + Boolean + + + + + + Alarm State + R + Single + Optional + Boolean + + + + + + Alarm Set Threshold + RW + Single + Optional + Float + + + + + + Alarm Set Operator + RW + Single + Optional + Integer + + + + + + Alarm Clear Threshold + RW + Single + Optional + Float + + + + + + Alarm Clear Operator + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Count + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Period + RW + Single + Optional + Integer + 1..864000 + s + + + + Latest Delivered Event Time + RW + Single + Optional + Time + + + + + + Latest Recorded Event Time + R + Single + Mandatory + Time + + + + + + Alarm Clear + E + Single + Optional + + + + + + + Alarm Auto Clear + RW + Single + Optional + Boolean + + + + + + Event Code + R + Single + Mandatory + Integer + 100..255 + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10274.xml b/transport/lwm2m/src/main/data/models/10274.xml new file mode 100644 index 0000000000..57d095d79c --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10274.xml @@ -0,0 +1,215 @@ + + + + + Water Meter Empty Pipe Alarm + + 10274 + urn:oma:lwm2m:x:10274 + Multiple + Optional + + + Event Type + RW + Single + Mandatory + Integer + + + + + + Alarm Realtime + RW + Single + Mandatory + Boolean + + + + + + Alarm State + R + Single + Optional + Boolean + + + + + + Alarm Set Threshold + RW + Single + Optional + Float + + + + + + Alarm Set Operator + RW + Single + Optional + Integer + + + + + + Alarm Clear Threshold + RW + Single + Optional + Float + + + + + + Alarm Clear Operator + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Count + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Period + RW + Single + Optional + Integer + 1..864000 + s + + + + Latest Delivered Event Time + RW + Single + Optional + Time + + + + + + Latest Recorded Event Time + R + Single + Mandatory + Time + + + + + + Alarm Clear + E + Single + Optional + + + + + + + Alarm Auto Clear + RW + Single + Optional + Boolean + + + + + + Event Code + R + Single + Mandatory + Integer + 100..255 + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10275.xml b/transport/lwm2m/src/main/data/models/10275.xml new file mode 100644 index 0000000000..7f88569cd4 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10275.xml @@ -0,0 +1,215 @@ + + + + + Water Meter Tamper Alarm + + 10275 + urn:oma:lwm2m:x:10275 + Multiple + Optional + + + Event Type + RW + Single + Mandatory + Integer + + + + + + Alarm Realtime + RW + Single + Mandatory + Boolean + + + + + + Alarm State + R + Single + Optional + Boolean + + + + + + Alarm Set Threshold + RW + Single + Optional + Float + + + + + + Alarm Set Operator + RW + Single + Optional + Integer + + + + + + Alarm Clear Threshold + RW + Single + Optional + Float + + + + + + Alarm Clear Operator + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Count + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Period + RW + Single + Optional + Integer + 1..864000 + s + + + + Latest Delivered Event Time + RW + Single + Optional + Time + + + + + + Latest Recorded Event Time + R + Single + Mandatory + Time + + + + + + Alarm Clear + E + Single + Optional + + + + + + + Alarm Auto Clear + RW + Single + Optional + Boolean + + + + + + Event Code + R + Single + Mandatory + Integer + 100..255 + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10276.xml b/transport/lwm2m/src/main/data/models/10276.xml new file mode 100644 index 0000000000..0a642a9774 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10276.xml @@ -0,0 +1,215 @@ + + + + + Water Meter High Pressure Alarm + + 10276 + urn:oma:lwm2m:x:10276 + Multiple + Optional + + + Event Type + RW + Single + Mandatory + Integer + + + + + + Alarm Realtime + RW + Single + Mandatory + Boolean + + + + + + Alarm State + R + Single + Optional + Boolean + + + + + + Alarm Set Threshold + RW + Single + Optional + Float + + + + + + Alarm Set Operator + RW + Single + Optional + Integer + + + + + + Alarm Clear Threshold + RW + Single + Optional + Float + + + + + + Alarm Clear Operator + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Count + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Period + RW + Single + Optional + Integer + 1..864000 + s + + + + Latest Delivered Event Time + RW + Single + Optional + Time + + + + + + Latest Recorded Event Time + R + Single + Mandatory + Time + + + + + + Alarm Clear + E + Single + Optional + + + + + + + Alarm Auto Clear + RW + Single + Optional + Boolean + + + + + + Event Code + R + Single + Mandatory + Integer + 100..255 + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10277.xml b/transport/lwm2m/src/main/data/models/10277.xml new file mode 100644 index 0000000000..d6dcdf92bc --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10277.xml @@ -0,0 +1,215 @@ + + + + + Water Meter Low Pressure Alarm + + 10277 + urn:oma:lwm2m:x:10277 + Multiple + Optional + + + Event Type + RW + Single + Mandatory + Integer + + + + + + Alarm Realtime + RW + Single + Mandatory + Boolean + + + + + + Alarm State + R + Single + Optional + Boolean + + + + + + Alarm Set Threshold + RW + Single + Optional + Float + + + + + + Alarm Set Operator + RW + Single + Optional + Integer + + + + + + Alarm Clear Threshold + RW + Single + Optional + Float + + + + + + Alarm Clear Operator + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Count + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Period + RW + Single + Optional + Integer + 1..864000 + s + + + + Latest Delivered Event Time + RW + Single + Optional + Time + + + + + + Latest Recorded Event Time + R + Single + Mandatory + Time + + + + + + Alarm Clear + E + Single + Optional + + + + + + + Alarm Auto Clear + RW + Single + Optional + Boolean + + + + + + Event Code + R + Single + Mandatory + Integer + 100..255 + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10278.xml b/transport/lwm2m/src/main/data/models/10278.xml new file mode 100644 index 0000000000..c2334e734f --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10278.xml @@ -0,0 +1,215 @@ + + + + + High Temperature Alarm + + 10278 + urn:oma:lwm2m:x:10278 + Multiple + Optional + + + Event Type + RW + Single + Mandatory + Integer + + + + + + Alarm Realtime + RW + Single + Mandatory + Boolean + + + + + + Alarm State + R + Single + Optional + Boolean + + + + + + Alarm Set Threshold + RW + Single + Optional + Float + + + + + + Alarm Set Operator + RW + Single + Optional + Integer + + + + + + Alarm Clear Threshold + RW + Single + Optional + Float + + + + + + Alarm Clear Operator + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Count + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Period + RW + Single + Optional + Integer + 1..864000 + s + + + + Latest Delivered Event Time + RW + Single + Optional + Time + + + + + + Latest Recorded Event Time + R + Single + Mandatory + Time + + + + + + Alarm Clear + E + Single + Optional + + + + + + + Alarm Auto Clear + RW + Single + Optional + Boolean + + + + + + Event Code + R + Single + Mandatory + Integer + 100..255 + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10279.xml b/transport/lwm2m/src/main/data/models/10279.xml new file mode 100644 index 0000000000..5875cabfa3 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10279.xml @@ -0,0 +1,215 @@ + + + + + Low Temperature Alarm + + 10279 + urn:oma:lwm2m:x:10279 + Multiple + Optional + + + Event Type + RW + Single + Mandatory + Integer + + + + + + Alarm Realtime + RW + Single + Mandatory + Boolean + + + + + + Alarm State + R + Single + Optional + Boolean + + + + + + Alarm Set Threshold + RW + Single + Optional + Float + + + + + + Alarm Set Operator + RW + Single + Optional + Integer + + + + + + Alarm Clear Threshold + RW + Single + Optional + Float + + + + + + Alarm Clear Operator + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Count + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Period + RW + Single + Optional + Integer + 1..864000 + s + + + + Latest Delivered Event Time + RW + Single + Optional + Time + + + + + + Latest Recorded Event Time + R + Single + Mandatory + Time + + + + + + Alarm Clear + E + Single + Optional + + + + + + + Alarm Auto Clear + RW + Single + Optional + Boolean + + + + + + Event Code + R + Single + Mandatory + Integer + 100..255 + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10280.xml b/transport/lwm2m/src/main/data/models/10280.xml new file mode 100644 index 0000000000..05d2fe9fd0 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10280.xml @@ -0,0 +1,215 @@ + + + + + Water Network Leak Alarm + + 10280 + urn:oma:lwm2m:x:10280 + Multiple + Optional + + + Event Type + RW + Single + Mandatory + Integer + + + + + + Alarm Realtime + RW + Single + Mandatory + Boolean + + + + + + Alarm State + R + Single + Optional + Boolean + + + + + + Alarm Set Threshold + RW + Single + Optional + Float + + + + + + Alarm Set Operator + RW + Single + Optional + Integer + + + + + + Alarm Clear Threshold + RW + Single + Optional + Float + + + + + + Alarm Clear Operator + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Count + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Period + RW + Single + Optional + Integer + 1..864000 + s + + + + Latest Delivered Event Time + RW + Single + Optional + Time + + + + + + Latest Recorded Event Time + R + Single + Mandatory + Time + + + + + + Alarm Clear + E + Single + Optional + + + + + + + Alarm Auto Clear + RW + Single + Optional + Boolean + + + + + + Event Code + R + Single + Mandatory + Integer + 100..255 + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10281.xml b/transport/lwm2m/src/main/data/models/10281.xml new file mode 100644 index 0000000000..5af65e535b --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10281.xml @@ -0,0 +1,215 @@ + + + + + Low Battery Alarm + + 10281 + urn:oma:lwm2m:x:10281 + Multiple + Optional + + + Event Type + RW + Single + Mandatory + Integer + + + + + + Alarm Realtime + RW + Single + Mandatory + Boolean + + + + + + Alarm State + R + Single + Optional + Boolean + + + + + + Alarm Set Threshold + RW + Single + Optional + Float + + + + + + Alarm Set Operator + RW + Single + Optional + Integer + + + + + + Alarm Clear Threshold + RW + Single + Optional + Float + + + + + + Alarm Clear Operator + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Count + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Period + RW + Single + Optional + Integer + 1..864000 + s + + + + Latest Delivered Event Time + RW + Single + Optional + Time + + + + + + Latest Recorded Event Time + R + Single + Mandatory + Time + + + + + + Alarm Clear + E + Single + Optional + + + + + + + Alarm Auto Clear + RW + Single + Optional + Boolean + + + + + + Event Code + R + Single + Mandatory + Integer + 100..255 + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10282.xml b/transport/lwm2m/src/main/data/models/10282.xml new file mode 100644 index 0000000000..3358e710c7 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10282.xml @@ -0,0 +1,215 @@ + + + + + Daughter Board Failure Alarm + + 10282 + urn:oma:lwm2m:x:10282 + Multiple + Optional + + + Event Type + RW + Single + Mandatory + Integer + + + + + + Alarm Realtime + RW + Single + Mandatory + Boolean + + + + + + Alarm State + R + Single + Optional + Boolean + + + + + + Alarm Set Threshold + RW + Single + Optional + Float + + + + + + Alarm Set Operator + RW + Single + Optional + Integer + + + + + + Alarm Clear Threshold + RW + Single + Optional + Float + + + + + + Alarm Clear Operator + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Count + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Period + RW + Single + Optional + Integer + 1..864000 + s + + + + Latest Delivered Event Time + RW + Single + Optional + Time + + + + + + Latest Recorded Event Time + R + Single + Mandatory + Time + + + + + + Alarm Clear + E + Single + Optional + + + + + + + Alarm Auto Clear + RW + Single + Optional + Boolean + + + + + + Event Code + R + Single + Mandatory + Integer + 100..255 + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10283.xml b/transport/lwm2m/src/main/data/models/10283.xml new file mode 100644 index 0000000000..b70c37371e --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10283.xml @@ -0,0 +1,215 @@ + + + + + Device Reboot Event + + 10283 + urn:oma:lwm2m:x:10283 + Multiple + Optional + + + Event Type + RW + Single + Mandatory + Integer + + + + + + Alarm Realtime + RW + Single + Mandatory + Boolean + + + + + + Alarm State + R + Single + Optional + Boolean + + + + + + Alarm Set Threshold + RW + Single + Optional + Float + + + + + + Alarm Set Operator + RW + Single + Optional + Integer + + + + + + Alarm Clear Threshold + RW + Single + Optional + Float + + + + + + Alarm Clear Operator + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Count + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Period + RW + Single + Optional + Integer + 1..864000 + s + + + + Latest Delivered Event Time + RW + Single + Optional + Time + + + + + + Latest Recorded Event Time + R + Single + Mandatory + Time + + + + + + Alarm Clear + E + Single + Optional + + + + + + + Alarm Auto Clear + RW + Single + Optional + Boolean + + + + + + Event Code + R + Single + Mandatory + Integer + 100..255 + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10284.xml b/transport/lwm2m/src/main/data/models/10284.xml new file mode 100644 index 0000000000..08b9a84d72 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10284.xml @@ -0,0 +1,215 @@ + + + + + Time Synchronisation Event + + 10284 + urn:oma:lwm2m:x:10284 + Multiple + Optional + + + Event Type + RW + Single + Mandatory + Integer + + + + + + Alarm Realtime + RW + Single + Mandatory + Boolean + + + + + + Alarm State + R + Single + Optional + Boolean + + + + + + Alarm Set Threshold + RW + Single + Optional + Float + + + + + + Alarm Set Operator + RW + Single + Optional + Integer + + + + + + Alarm Clear Threshold + RW + Single + Optional + Float + + + + + + Alarm Clear Operator + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Count + RW + Single + Optional + Integer + + + + + + Alarm Maximum Event Period + RW + Single + Optional + Integer + 1..864000 + s + + + + Latest Delivered Event Time + RW + Single + Optional + Time + + + + + + Latest Recorded Event Time + R + Single + Mandatory + Time + + + + + + Alarm Clear + E + Single + Optional + + + + + + + Alarm Auto Clear + RW + Single + Optional + Boolean + + + + + + Event Code + R + Single + Mandatory + Integer + 100..255 + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10286.xml b/transport/lwm2m/src/main/data/models/10286.xml new file mode 100644 index 0000000000..2ac0cf71fb --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10286.xml @@ -0,0 +1,65 @@ + + + + + App Fota Container + + 10286 + urn:oma:lwm2m:x:10286 + 1.0 + 1.0 + Single + Optional + + + UL data + R + Single + Mandatory + Opaque + + + + + + + + DL data + W + Single + Mandatory + Opaque + + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10290.xml b/transport/lwm2m/src/main/data/models/10290.xml new file mode 100644 index 0000000000..a4f6262d9c --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10290.xml @@ -0,0 +1,183 @@ + + + + + Voltage Logging + + 10290 + urn:oma:lwm2m:x:10290 + 1.0 + 1.0 + Multiple + Optional + + + Interval Period + R + Single + Mandatory + Integer + 1..864000 + s + + + + Interval Start Offset + R + Single + Optional + Integer + 0..86399 + s + + + + Interval UTC Offset + R + Single + Optional + String + + + + + + Interval Collection Start Time + R + Single + Mandatory + Time + + + + + + Oldest Recorded Interval + R + Single + Mandatory + Time + + + + + + Last Delivered Interval + RW + Single + Optional + Time + + + + + + Latest Recorded Interval + R + Single + Mandatory + Time + + + + + + Interval Delivery Midnight Aligned + RW + Single + Mandatory + Boolean + + + + + + Interval Historical Read + E + Single + Optional + + + + + + + Interval Historical Read Payload + R + Single + Optional + Opaque + + + + + + Interval Change Configuration + E + Single + Optional + + + + + + + Start + E + Single + Optional + + + + + + + Stop + E + Single + Optional + + + + + + + Status + R + Single + Optional + Integer + + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10291.xml b/transport/lwm2m/src/main/data/models/10291.xml new file mode 100644 index 0000000000..bd6de7cd34 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10291.xml @@ -0,0 +1,193 @@ + + + + + Voltage Transient + + 10291 + urn:oma:lwm2m:x:10291 + 1.0 + 1.0 + Multiple + Optional + + + Interval Period + R + Single + Mandatory + Integer + 1..864000 + s + + + + Interval Start Offset + R + Single + Mandatory + Integer + 0..86399 + s + + + + Interval UTC Offset + R + Single + Optional + String + + + + + + Interval Collection Start Time + R + Single + Mandatory + Time + + + + + + Oldest Recorded Interval + R + Single + Mandatory + Time + + + + + + Last Delivered Interval + RW + Single + Mandatory + Time + + + + + + Latest Recorded Interval + R + Single + Mandatory + Time + + + + + + Interval Delivery Midnight Aligned + RW + Single + Mandatory + Boolean + + + + + + Interval Historical Read + E + Single + Optional + + + + + + + Interval Historical Read Payload + R + Single + Optional + Opaque + + + + + + Interval Change Configuration + E + Single + Optional + + + + + + + Start + E + Single + Optional + + + + + + + Stop + E + Single + Optional + + + + + + + Status + R + Single + Optional + Integer + + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + Sample Frequency + RW + Single + Mandatory + Float + 0.0..86400.0 + s + How often the inputs are read/sampled.This value can be changed by doing a write command + + + + + diff --git a/transport/lwm2m/src/main/data/models/10292.xml b/transport/lwm2m/src/main/data/models/10292.xml new file mode 100644 index 0000000000..0637afed2a --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10292.xml @@ -0,0 +1,193 @@ + + + + + Pressure Transient + + 10292 + urn:oma:lwm2m:x:10292 + 1.0 + 1.0 + Multiple + Optional + + + Interval Period + R + Single + Mandatory + Integer + 1..864000 + s + + + + Interval Start Offset + R + Single + Mandatory + Integer + 0..86399 + s + + + + Interval UTC Offset + R + Single + Optional + String + + + + + + Interval Collection Start Time + R + Single + Mandatory + Time + + + + + + Oldest Recorded Interval + R + Single + Mandatory + Time + + + + + + Last Delivered Interval + RW + Single + Mandatory + Time + + + + + + Latest Recorded Interval + R + Single + Mandatory + Time + + + + + + Interval Delivery Midnight Aligned + RW + Single + Mandatory + Boolean + + + + + + Interval Historical Read + E + Single + Optional + + + + + + + Interval Historical Read Payload + R + Single + Optional + Opaque + + + + + + Interval Change Configuration + E + Single + Optional + + + + + + + Start + E + Single + Optional + + + + + + + Stop + E + Single + Optional + + + + + + + Status + R + Single + Optional + Integer + + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + Sample Frequency + RW + Single + Mandatory + Float + 0.0..86400.0 + s + How often the inputs are read/sampled.This value can be changed by doing a write command + + + + + diff --git a/transport/lwm2m/src/main/data/models/10299.xml b/transport/lwm2m/src/main/data/models/10299.xml new file mode 100644 index 0000000000..c97b9b3ba4 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10299.xml @@ -0,0 +1,130 @@ + + + + + + + + HostDevice + This LWM2M Object provides a range of host device related information which can be queried by the LWM2M Server. The host device is any integrated device with an embedded cellular radio module. + 10299 + urn:oma:lwm2m:x:10299 + 1.0 + 1.0 + Single + Optional + + + Manufacturer + R + Single + Mandatory + String + + + Host device manufacturers name (OEM). + + + Model + R + Single + Mandatory + String + + Identifier of the model name or number determined by device manufacturer. + UniqueID + R + Single + Mandatory + String + + + Unique ID assigned by an manufacturer or other body. Used to uniquely identify a host device. Examples include serial # or UUID. + + + FirmwareVersion + R + Single + Mandatory + String + + + Current Firmware version of the host device. (manufacturer specified string). + + SoftwareVersion + R + Single + Optional + String + + + Current software version of the host device. (manufacturer specified string). + + HardwareVersion + R + Single + Optional + String + + + Current hardware version of the host device. (manufacturer specified string). + + + DateStamp + R + Single + Optional + String + + + UTC value of the time and date of the last Firmware or Software update. Format:MM:DD:YYYY HH:MM:SS + + + + + diff --git a/transport/lwm2m/src/main/data/models/10300.xml b/transport/lwm2m/src/main/data/models/10300.xml new file mode 100644 index 0000000000..4b710f38f5 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10300.xml @@ -0,0 +1,142 @@ + + + + + LWM2M Meta Object + + + + 10300 + urn:oma:lwm2m:x:10300 + 1.0 + 1.0 + Multiple + Optional + + + ObjectID + R + Single + Mandatory + Integer + + + + + + + + ObjectURN + R + Single + Mandatory + String + + + + + + + + ObjectInstanceHandle + R + Single + Optional + Objlnk + + + + + + + + URI + R + Multiple + Mandatory + String + + + + + + + + SHAType + R + Single + Optional + Integer + 0..8 + + + + + + + ChecksumValue + R + Single + Optional + String + + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10308-2_0.xml b/transport/lwm2m/src/main/data/models/10308-2_0.xml new file mode 100644 index 0000000000..d119c7d239 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10308-2_0.xml @@ -0,0 +1,130 @@ + + + + + AT&T Connectivity Extension + + 10308 + urn:oma:lwm2m:x:10308:2.0 + 1.0 + 2.0 + Multiple + Optional + + + ICCID + R + Single + Mandatory + String + + + + + + + IMSI + R + Single + Mandatory + String + + + + + + + MSISDN + RW + Single + Mandatory + String + + + + + + + APN Retries + RW + Single + Mandatory + Integer + + + + + + + APN Retry Period + RW + Single + Mandatory + Integer + + + s + + + + APN Retry Back-Off Period + RW + Single + Mandatory + Integer + + + s + + + + SINR + R + Single + Mandatory + Integer + <7 to >12.5 + + + + + SRXLEV + R + Single + Mandatory + Integer + + + + + + + CE_LEVEL + R + Single + Mandatory + Integer + 0,1,2 + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10309.xml b/transport/lwm2m/src/main/data/models/10309.xml new file mode 100644 index 0000000000..ba60d0906f --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10309.xml @@ -0,0 +1,114 @@ + + + + + Shareparkinglot + + 10309 + urn:oma:lwm2m:x:10309 + 1.0 + 1.0 + Multiple + Optional + + + LockID + R + Single + Mandatory + Integer + + + + + + LockType + R + Single + Optional + String + + + + + + LightSwitchState + R + Multiple + Optional + Boolean + + + + + + RSSI + R + Multiple + Mandatory + Integer + -30..-120 + dBm + + + + BatteryCapacity + R + Multiple + Optional + Float + 0..100 + %EL + + + + DataUpTime + R + Multiple + Mandatory + Time + + + + + + Latitude + R + Multiple + Optional + String + + + + + + Longitude + R + Multiple + Optional + String + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10311.xml b/transport/lwm2m/src/main/data/models/10311.xml new file mode 100644 index 0000000000..81b3bb69b7 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10311.xml @@ -0,0 +1,149 @@ + + + + + Solar Radiation + + This object is used to report solar irradiance (SI), i.e. power per unit area received from the Sun in the form of electromagnetic radiation, on a planar surface measured by a pyranometer or similar instrument. A pyranometer measures solar irradiance from the hemisphere above within a wavelength range 0.3 μm to 3 μm. For example, the application of solar radiation measurement can be meteorological networks and solar energy applications. + + 10311 + urn:oma:lwm2m:x:10311 + 1.0 + 1.0 + Multiple + Optional + + + Min Measured Value + R + Single + Optional + Float + + + + The minimum value measured by the sensor since it is ON or Reset, expressed in the unit defined by the "Sensor Units" resource if present. + + + + Max Measured Value + R + Single + Optional + Float + + + + The maximum value measured by the sensor since it is ON or Reset, expressed in the unit defined by the "Sensor Units" resource if present. + + + + Min Range Value + R + Single + Optional + Float + + + + The minimum value that can be measured by the sensor, expressed in the unit defined by the "Sensor Units" resource if present. + + + + Max Range Value + R + Single + Optional + Float + + + + The maximum value that can be measured by the sensor, expressed in the unit defined by the "Sensor Units" resource if present. + + + + Reset Min and Max Measured Values + E + Single + Optional + + + + + Reset the Min and Max Measured Values to current value. + + + + Timestamp + R + Single + Optional + Time + + + The timestamp of when the measurement was performed. + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor expressed in the unit defined by the "Sensor Units" resource if present. + + + Sensor Units + R + Single + Optional + String + + + + Measurement Units Definition. + + + + Application Type + RW + Single + Optional + String + + + + The application type of the sensor or actuator as a string, for instance "Air Pressure". + + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + + + diff --git a/transport/lwm2m/src/main/data/models/10313.xml b/transport/lwm2m/src/main/data/models/10313.xml new file mode 100644 index 0000000000..e13fefcb23 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10313.xml @@ -0,0 +1,238 @@ + + + + + Gas Readings + + 10313 + urn:oma:lwm2m:x:103131.0 + 1.0Multiple + Optional + + + Interval Period + R + Single + Mandatory + Integer + 1..864000 + s + + + + Interval Start Offset + R + Single + Optional + Integer + 0..86399 + s + + + + Interval UTC Offset + R + Single + Optional + String + + + + + + Interval Collection Start Time + R + Single + Mandatory + Time + + + + + + Oldest Recorded Interval + R + Single + Mandatory + Time + + + + + + Last Delivered Interval + RW + Single + Optional + Time + + + + + + Latest Recorded Interval + R + Single + Mandatory + Time + + + + + + Interval Delivery Midnight Aligned + RW + Single + Mandatory + Boolean + + + + + + Interval Historical Read + E + Single + Optional + + + + + + + Interval Historical Read Payload + R + Single + Optional + Opaque + + + + + + Interval Change Configuration + E + Single + Optional + + + + + + + Start + E + Single + Optional + + + + + + + Stop + E + Single + Optional + + + + + + + Status + R + Single + Optional + Integer + + + + + + Latest Payload + R + Single + Mandatory + Opaque + + + + + + Sensor Warm-up Time + RW + Single + Optional + Integer + 0..86400 + s + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10314.xml b/transport/lwm2m/src/main/data/models/10314.xml new file mode 100644 index 0000000000..0229469801 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10314.xml @@ -0,0 +1,113 @@ + + + + + Particulates + + 10314 + urn:oma:lwm2m:x:10314 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + + + + Min Measured Value + R + Single + Optional + Float + + + + + + Max Measured Value + R + Single + Optional + Float + + + + + + Max Range Value + R + Single + Optional + Float + + + + + + Sensor Units + R + Single + Optional + String + + + + + + Application Type + RW + Single + Optional + String + + + The Application type of the device, for example “Particulate Sensor”. + + + Reset Min and Max Measured Values + E + Single + Optional + + + + + + + Measured Particle Size + R + Single + Mandatory + Float + + m + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10315.xml b/transport/lwm2m/src/main/data/models/10315.xml new file mode 100644 index 0000000000..9886eb7bd0 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10315.xml @@ -0,0 +1,115 @@ + + + + + Robot + + 10315 + urn:oma:lwm2m:x:10315 + 1.0 + 1.0 + Single + Mandatory + + + Robot ID + R + Single + Mandatory + String + 0..255 + + + + + Robot Type + R + Single + Mandatory + String + 0..63 + + + + + Robot Serial Number + R + Single + Mandatory + String + 0..63 + + + + + Battery Level + R + Single + Mandatory + Integer + 0..100 + % + + + + Charging + R + Single + Mandatory + Boolean + + + + + + On time + RW + Single + Mandatory + Integer + + s + + + + Positioning + R + Single + Optional + Boolean + + + + + + Location + R + Single + Optional + Objlnk + + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10316.xml b/transport/lwm2m/src/main/data/models/10316.xml new file mode 100644 index 0000000000..3fbb549858 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10316.xml @@ -0,0 +1,219 @@ + + + + + RCU + + 10316 + urn:oma:lwm2m:x:10316 + 1.0 + 1.0 + Single + Mandatory + + + RCU ID + R + Single + Mandatory + String + 0..127 + + + + + RCU Serial Number + R + Single + Mandatory + String + 0..63 + + + + + RCU Software Version + R + Single + Mandatory + String + 0..63 + + + + + RCU OS Version + R + Single + Mandatory + String + 0..127 + + + + + RCU CPU Info + R + Single + Mandatory + String + 64 + + + + + RCU RAM Info + R + Single + Mandatory + String + 64 + + + + + RCU ROM Size + R + Single + Mandatory + Integer + + GB + + + + RCU ROM Available Size + R + Single + Mandatory + Integer + + GB + + + + SD Storage + R + Single + Mandatory + Integer + + GB + + + + SD Available Storage + R + Single + Mandatory + Integer + + GB + + + + RCU GPS Location + R + Single + Optional + Objlnk + + + + + + Wi-Fi MAC + R + Single + Optional + String + 12 + + + + + Bluetooth MAC + R + Single + Optional + String + 12 + + + + + Camera Info + R + Single + Optional + String + 64 + + + + + + Battery Level + R + Single + Mandatory + Integer + 0..100 + /100 + + + + + On time + RW + Single + Mandatory + Integer + + s + + + + + Downloaded APP Packages + R + Multiple + Mandatory + String + + + + + + + RCU APPs + R + Multiple + Optional + Objlnk + + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10318.xml b/transport/lwm2m/src/main/data/models/10318.xml new file mode 100644 index 0000000000..3db4c92fd8 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10318.xml @@ -0,0 +1,175 @@ + + + + + RCU PM + + 10318 + urn:oma:lwm2m:x:10318 + 1.0 + 1.0 + Single + Mandatory + + + CPU Usage + R + Single + Mandatory + Integer + 0..100 + /100 + + + + Max CPU Usage + R + Single + Mandatory + Integer + 0..100 + /100 + + + + Memory Usage + R + Single + Mandatory + Integer + 0..100 + /100 + + + + Storage Usage + R + Single + Mandatory + Integer + 0..100 + /100 + + + + + Battery Level + R + Single + Mandatory + Integer + 0..100 + /100 + + + + Network Bandwidth + R + Single + Mandatory + Float + + Mbit/s + + + + Mobile Signal + R + Single + Mandatory + Integer + + + + + + GPS Signal + R + Single + Optional + Integer + + + + + + Wi-Fi Signal + R + Single + Mandatory + Integer + + + + + + UpLink Rate + R + Single + Mandatory + Float + + Mbit/s + + + + DownLink Rate + R + Single + Mandatory + Float + + Mbit/s + + + + Packet Loss Rate + R + Single + Mandatory + Integer + 0..100 + /100 + + + + Network Latency + R + Single + Mandatory + Integer + + ms + + + + + Battery Temperature + R + Single + Mandatory + Float + + Cel + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10319.xml b/transport/lwm2m/src/main/data/models/10319.xml new file mode 100644 index 0000000000..c3c25871f4 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10319.xml @@ -0,0 +1,116 @@ + + + + + RCU Control + + 10319 + urn:oma:lwm2m:x:10319 + 1.0 + 1.0 + Single + Mandatory + + + RCU Diagnostics Mode + R + Single + Optional + Boolean + + + + + + RCU Log Recording + R + Single + Optional + Boolean + + + + + + + RCU Shutdown + E + Single + Mandatory + + + + + + + RCU Restart + E + Single + Mandatory + + + + + + + RCU Deactivate + E + Single + Mandatory + + + + + + + RCU Reset + E + Single + Mandatory + + + + + + + RCU Diagnostics Mode Control + E + Single + Mandatory + + + + + + + RCU Log Recording Control + E + Single + Mandatory + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10320.xml b/transport/lwm2m/src/main/data/models/10320.xml new file mode 100644 index 0000000000..47a4c2e147 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10320.xml @@ -0,0 +1,127 @@ + + + + + CCU + + 10320 + urn:oma:lwm2m:x:10320 + 1.0 + 1.0 + Multiple + Optional + + + CCU ID + R + Single + Mandatory + String + + + + + + CCU FM Version + R + Single + Mandatory + String + + + + + + CCU SW Version + R + Single + Mandatory + String + + + + + + CCU Memory Size + R + Single + Mandatory + Integer + + GB + + + + CCU Storage + R + Single + Mandatory + Integer + + GB + + + + CCU Available Storage + R + Single + Mandatory + Integer + + GB + + + + + On time + RW + Single + Mandatory + Integer + + s + + + + + Downloaded APP Packages + R + Multiple + Optional + String + + + + + + CCU APPs + R + Multiple + Optional + Objlnk + + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10322.xml b/transport/lwm2m/src/main/data/models/10322.xml new file mode 100644 index 0000000000..5375bdd97d --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10322.xml @@ -0,0 +1,73 @@ + + + + + CCU PM + + 10322 + urn:oma:lwm2m:x:10322 + 1.0 + 1.0 + Multiple + Optional + + + CPU Usage + R + Single + Optional + Integer + 0..100 + % + + + + Max CPU Usage + R + Single + Optional + Integer + 0..100 + % + + + + Memory Usage + R + Single + Optional + Integer + 0..100 + % + + + + Storage Usage + R + Single + Optional + Integer + 0..100 + % + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10323.xml b/transport/lwm2m/src/main/data/models/10323.xml new file mode 100644 index 0000000000..4d9ff0a253 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10323.xml @@ -0,0 +1,76 @@ + + + + + CCU Control + + 10323 + urn:oma:lwm2m:x:10323 + 1.0 + 1.0 + Multiple + Optional + + + + CCU Restart + E + Single + Mandatory + + + + + + + CCU Reset + E + Single + Mandatory + + + + + + + CCU Self-checking + E + Single + Mandatory + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10324.xml b/transport/lwm2m/src/main/data/models/10324.xml new file mode 100644 index 0000000000..8535a3f5b1 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10324.xml @@ -0,0 +1,63 @@ + + + + + ECU + + 10324 + urn:oma:lwm2m:x:10324 + 1.0 + 1.0 + Multiple + Optional + + + ECU ID + R + Single + Mandatory + String + + + + + + ECU FM Version + R + Single + Mandatory + String + + + + + + On time + RW + Single + Mandatory + Integer + + s + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10326.xml b/transport/lwm2m/src/main/data/models/10326.xml new file mode 100644 index 0000000000..788c33416a --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10326.xml @@ -0,0 +1,708 @@ + + + + + Robot PM + + 10326 + urn:oma:lwm2m:x:10326 + 1.0 + 1.0 + Single + Mandatory + + + Battery Level + R + Single + Mandatory + Integer + 0..100 + /100 + + + + + Battery Temperature + R + Single + Mandatory + Integer + + Cel + + + + Temperature + R + Single + Optional + Float + + Cel + + + + Humidity + R + Single + Optional + Integer + 0..100 + /100 + + + + PM2.5 + R + Single + Optional + Integer + + ug/m3 + + + + Smog + R + Single + Optional + Float + + ug/m3 + + + + CO + R + Single + Optional + Float + + ppm + + + + CO2 + R + Single + Optional + Float + + ppm + + + + PM10 + R + Single + Optional + Integer + + ug/m3 + + + + Speed + R + Single + Optional + Float + + m/h + + + + Water Used + R + Single + Optional + Integer + 0..100 + /100 + + + + Dust Box Used + R + Single + Optional + Integer + 0..100 + /100 + + + + Obstacle Distance + R + Single + Optional + Integer + + cm + + + + + Robot Temperate + R + Single + Optional + Float + + Cel + + + + Confidence Index + R + Single + Optional + Integer + 0..100 + /100 + + + + + Data Traffic Used + R + Single + Mandatory + Float + + Mbit/s + + + + Images Handled + R + Single + Optional + Integer + + + + + + HARI S-Voice Requests + R + Single + Optional + Integer + + + + + + HARI S-Vision Requests + R + Single + Optional + Integer + + + + + + HARI S-Motion Requests + R + Single + Optional + Integer + + + + + + HARI S-Map Requests + R + Single + Optional + Integer + + + + + + Successful HARI S-Voice Requests + R + Single + Optional + Integer + + + + + + Successful HARI S-Vision Requests + R + Single + Optional + Integer + + + + + + Successful HARI S-Motion Requests + R + Single + Optional + Integer + + + + + + Successful HARI S-Map Requests + R + Single + Optional + Integer + + + + + + Questions Answered + R + Single + Optional + Integer + + + + + + Unknown Questions + R + Single + Optional + Integer + + + + + + Mileage + R + Single + Optional + Integer + + m + + + + Cleaned Times + R + Single + Optional + Integer + + + + + + Cleaned Area + R + Single + Optional + Float + + m2 + + + + Cleaned Time + R + Single + Optional + Integer + + s + + + + ASR Recognized + R + Single + Optional + Integer + + B + + + + Incorrect ASR Recognitions + R + Single + Optional + Integer + + B + + + + Tried TTS Texts + R + Single + Optional + Integer + + B + + + + Successful TTS Texts + R + Single + Optional + Integer + + B + + + + ASR Recognized (CH) + R + Single + Optional + Integer + + B + + + + Tried TTS Texts (CH) + R + Single + Optional + Integer + + B + + + + Successful TTS Texts (CH) + R + Single + Optional + Integer + + B + + + + ASR Recognized (EN) + R + Single + Optional + Integer + + B + + + + Tried TTS Texts (EN) + R + Single + Optional + Integer + + B + + + + Successful TTS Texts (EN) + R + Single + Optional + Integer + + B + + + + ASR Recognized (ES) + R + Single + Optional + Integer + + B + + + + Tried TTS Texts (ES) + R + Single + Optional + Integer + + B + + + + Successful TTS Texts (ES) + R + Single + Optional + Integer + + B + + + + ASR Recognized (JA) + R + Single + Optional + Integer + + B + + + + Tried TTS Texts (JA) + R + Single + Optional + Integer + + B + + + + Successful TTS Texts (JA) + R + Single + Optional + Integer + + B + + + + ASR Recognized (SCCH) + R + Single + Optional + Integer + + B + + + + Tried TTS Texts (SCCH) + R + Single + Optional + Integer + + B + + + + Successful TTS Texts (SCCH) + R + Single + Optional + Integer + + B + + + + ASR Recognized (GDCH) + R + Single + Optional + Integer + + B + + + + Tried TTS Texts (GDCH) + R + Single + Optional + Integer + + B + + + + Successful TTS Texts (GDCH) + R + Single + Optional + Integer + + B + + + + ASR Recognized (TCH) + R + Single + Optional + Integer + + B + + + + Tried TTS Texts (TCH) + R + Single + Optional + Integer + + B + + + + Successful TTS Texts (TCH) + R + Single + Optional + Integer + + B + + + + + Objects Recognition Tries + R + Single + Optional + Integer + + + + + + Successful Object Recognition + R + Single + Optional + Integer + + + + + + Face Recognition Tries + R + Single + Optional + Integer + + + + + + Successful Face Recognitions + R + Single + Optional + Integer + + + + + + Vehicle Plate Recognition Tries + R + Single + Optional + Integer + + + + + + Successful Vehicle Plate Recognitions + R + Single + Optional + Integer + + + + + + Tasks Assigned + R + Single + Mandatory + Integer + + + + + + Successful Tasks Executed + R + Single + Mandatory + Integer + + + + + + Images Uploaded + R + Single + Optional + Integer + + + + + + Videos Uploaded + R + Single + Optional + Integer + + + + + + Images Matted + R + Single + Optional + Integer + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10327.xml b/transport/lwm2m/src/main/data/models/10327.xml new file mode 100644 index 0000000000..3e30093d21 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10327.xml @@ -0,0 +1,54 @@ + + + + + Compressor + + 10327 + urn:oma:lwm2m:x:10327 + 1.0 + 1.0 + Multiple + Optional + + + Compressor Name + R + Single + Mandatory + String + + + + + + + Compressor Status + R + Single + Mandatory + Boolean + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10328.xml b/transport/lwm2m/src/main/data/models/10328.xml new file mode 100644 index 0000000000..f0e69ccb44 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10328.xml @@ -0,0 +1,66 @@ + + + + + SCA PM + + 10328 + urn:oma:lwm2m:x:10328 + 1.0 + 1.0 + Multiple + Optional + + + SCA Name + R + Single + Mandatory + String + + + + + + + + + SCA Current + R + Single + Mandatory + Float + + A + + + + SCA Temperate + R + Single + Mandatory + Float + + Cel + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10329.xml b/transport/lwm2m/src/main/data/models/10329.xml new file mode 100644 index 0000000000..f4e3247416 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10329.xml @@ -0,0 +1,419 @@ + + + + + Robot Control + + 10329 + urn:oma:lwm2m:x:10329 + 1.0 + 1.0 + Single + Mandatory + + + Collision Detection + R + Single + Optional + Boolean + + + + + + Drop Detection + R + Single + Optional + Boolean + + + + + + Automatic Navigation + R + Single + Optional + Boolean + + + + + + Robot Shutdown + E + Single + Mandatory + + + + + + + Robot Reboot + E + Single + Mandatory + + + + + + + Robot Reset + E + Single + Mandatory + + + + + + + Robot Wakeup + E + Single + Mandatory + + + + + + + Robot Sleep + E + Single + Mandatory + + + + + + + Robot Self-checking + E + Single + Mandatory + + + + + + + Emergency Braking + E + Single + Mandatory + + + + + + + Emergency Braking Release + E + Single + Mandatory + + + + + + + Action Execution + E + Single + Optional + + + + + + + Action List Upload + E + Single + Optional + + + + + + + Action List Download + E + Single + Optional + + + + + + + Group Dancing Program Control + E + Single + Optional + + + + + + + Navigation Map Upload + E + Single + Optional + + + + + + + Group Dancing Program Control + E + Single + Optional + + + + + + + Navigation Map Download + E + Single + Optional + + + + + + + Route list Execution + E + Single + Optional + + + + + + + Route list Upload + E + Single + Optional + + + + + + + Route list Download + E + Single + Optional + + + + + + + Automatic Navigation Control + E + Single + Optional + + + + + + + Manual Navigation + E + Single + Optional + + + + + + + Moving to Charging Station + E + Single + Optional + + + + + + + Moving to Specified location + E + Single + Optional + + + + + + + Low Frequency Patrol Broadcasting + E + Single + Optional + + + + + + + Task Start + E + Single + Optional + + + + + + + Task Stop + E + Single + Optional + + + + + + + Task Suspend + E + Single + Optional + + + + + + + Task Resume + E + Single + Optional + + + + + + + Video Upload + E + Single + Optional + + + + + + + Picture Upload + E + Single + Optional + + + + + + + Default Language Switching + E + Single + Optional + + + + + + + Intonation Change + E + Single + Optional + + + + + + + Intonation Change + E + Single + Optional + + + + + + + Speaking with Action + E + Single + Optional + + + + + + + Collision Detection Control + E + Single + Mandatory + + + + + + + Drop Detection Control + E + Single + Mandatory + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10330.xml b/transport/lwm2m/src/main/data/models/10330.xml new file mode 100644 index 0000000000..8b37ec3966 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10330.xml @@ -0,0 +1,106 @@ + + + + + Network Info + + 10330 + urn:oma:lwm2m:x:10330 + 1.0 + 1.0 + Single + Mandatory + + + IMEI + R + Single + Mandatory + String + 15 + + + + + IMSI + R + Single + Mandatory + String + 15 + + + + + Radio Connectivity + R + Single + Mandatory + Objlnk + + + + + + + + GPS Signal Status + R + Single + Optional + Integer + 1..4 + + + + + VBN Connection Status + R + Single + Mandatory + Integer + 0..1 + + + + + HARI Connection Status + R + Single + Mandatory + Integer + 0..1 + + + + + CCU Connection Status + R + Multiple + Optional + Integer + 0..1 + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10331.xml b/transport/lwm2m/src/main/data/models/10331.xml new file mode 100644 index 0000000000..305f213cb0 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10331.xml @@ -0,0 +1,207 @@ + + + + + Robot Service Info + + 10331 + urn:oma:lwm2m:x:10331 + 1.0 + 1.0 + Single + Mandatory + + + Current status + R + Single + Mandatory + String + 0..127 + + + + + Services Providing + R + Single + Optional + String + 0..127 + + + + + Advertising Contents + R + Single + Mandatory + String + + + + + + Current Language + R + Single + Optional + String + 0..127 + + + + + Volume + R + Single + Optional + String + 0..100 + /100 + + + + Moving Status + R + Single + Optional + Integer + 0..2 + + + + + Moving Speed + R + Single + Optional + Float + + m/h + + + + Location + R + Single + Optional + Objlnk + + + + + + + + Map List + R + Single + Optional + String + + + + + + Planned Route list + R + Single + Optional + String + + + + + + Current Route + R + Single + Optional + String + + + + + + Route to-do List + R + Single + Optional + String + + + + + + Synchronous Whistle + R + Single + Mandatory + Boolean + + + + + + Current Actions + R + Single + Optional + String + + + + + + ASR Type + R + Single + Optional + Integer + 0..2 + + + + + + TTS Vendor + R + Single + Optional + String + + + + + + TTS Speaker + R + Single + Optional + String + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10332.xml b/transport/lwm2m/src/main/data/models/10332.xml new file mode 100644 index 0000000000..7581fa59a7 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10332.xml @@ -0,0 +1,55 @@ + + + + + Robot Selfcheck Info + + 10332 + urn:oma:lwm2m:x:10332 + 1.0 + 1.0 + Multiple + Optional + + + Entity + R + Single + Mandatory + String + 4..63 + + + + + + + Status + R + Single + Mandatory + Integer + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10333.xml b/transport/lwm2m/src/main/data/models/10333.xml new file mode 100644 index 0000000000..e6d3dda2a6 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10333.xml @@ -0,0 +1,74 @@ + + + + + PM Threshold + + 10333 + urn:oma:lwm2m:x:10333 + 1.0 + 1.0 + Single + Optional + + + Entity + RW + Multiple + Mandatory + String + 4..63 + + + + + Performance Type + RW + Multiple + Mandatory + String + + + + + + High Threshold + RW + Multiple + Mandatory + Float + + + + + + Low Threshold + RW + Multiple + Mandatory + Float + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10334.xml b/transport/lwm2m/src/main/data/models/10334.xml new file mode 100644 index 0000000000..55b7863f66 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10334.xml @@ -0,0 +1,115 @@ + + + + + Robot Alarm + + 10334 + urn:oma:lwm2m:x:10334 + 1.0 + 1.0 + Multiple + Optional + + + Entity + R + Single + Mandatory + String + 4..63 + + + + + Probable Cause + R + Single + Mandatory + Integer + 0..65535 + + + + + Specific Problem + R + Single + Mandatory + String + + + + + + Alarm Type + R + Single + Mandatory + Integer + 2..6 + + + + + Severity + R + Single + Mandatory + Integer + 1..5 + + + + + Report Time + R + Single + Mandatory + Time + + + + + + Sequence No + R + Single + Mandatory + Integer + 0..2^63-1 + + + + + Additional Info + R + Single + Optional + String + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10335.xml b/transport/lwm2m/src/main/data/models/10335.xml new file mode 100644 index 0000000000..3917feb001 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10335.xml @@ -0,0 +1,83 @@ + + + + + Event + + 10335 + urn:oma:lwm2m:x:10335 + 1.0 + 1.0 + Multiple + Optional + + + Entity + R + Single + Mandatory + String + 4..63 + + + + + Event Type + R + Single + Mandatory + Integer + 0..65535 + + + + + Time + R + Single + Mandatory + Time + + + + + + Sequence No + R + Single + Mandatory + Integer + 0..2^63-1 + + + + + Additional Info + R + Single + Optional + String + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10336.xml b/transport/lwm2m/src/main/data/models/10336.xml new file mode 100644 index 0000000000..57211a3819 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10336.xml @@ -0,0 +1,70 @@ + + + + + MIC + + 10336 + urn:oma:lwm2m:x:10336 + 1.0 + 1.0 + Single + Optional + + + Host Device Unique ID + R + Single + Optional + String + + + + + + + + Host Device Manufacturer + R + Single + Optional + String + + + + + + + + Host Device Model Number + R + Single + Optional + String + + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10337.xml b/transport/lwm2m/src/main/data/models/10337.xml new file mode 100644 index 0000000000..abbaf23cdf --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10337.xml @@ -0,0 +1,104 @@ + + + + + SCA + + 10337 + urn:oma:lwm2m:x:10337 + 1.0 + 1.0 + Multiple + Optional + + + SCA Name + R + Single + Mandatory + String + + + + + + + + + + SCA Motion Status + R + Single + Optional + Integer + 0..2 + + + + + + SCA Motion Control + E + Single + Optional + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10338.xml b/transport/lwm2m/src/main/data/models/10338.xml new file mode 100644 index 0000000000..c4793d625b --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10338.xml @@ -0,0 +1,110 @@ + + + + + Speaker + + 10338 + urn:oma:lwm2m:x:10338 + 1.0 + 1.0 + Single + Optional + + + Speaker status + R + Single + Mandatory + Boolean + + + + + + Voice Warning + R + Single + Mandatory + Boolean + + + + + + + Voice Control + E + Single + Mandatory + + + + + + + Voice Warning Control + E + Single + Mandatory + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10339.xml b/transport/lwm2m/src/main/data/models/10339.xml new file mode 100644 index 0000000000..7f3ae3d63b --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10339.xml @@ -0,0 +1,100 @@ + + + + + Tripod Head + + 10339 + urn:oma:lwm2m:x:10339 + 1.0 + 1.0 + Single + Optional + + + Host Device Unique ID + R + Single + Optional + String + + + + + + + + Host Device Manufacturer + R + Single + Optional + String + + + + + + + + Host Device Model Number + R + Single + Optional + String + + + + + + + + Tripod Direction Control + E + Single + Optional + + + + + + + Tripod Automatic Control + E + Single + Optional + + + + + + + Tripod Reset + E + Single + Optional + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10340.xml b/transport/lwm2m/src/main/data/models/10340.xml new file mode 100644 index 0000000000..d602833ddc --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10340.xml @@ -0,0 +1,204 @@ + + + + + Camera + + 10340 + urn:oma:lwm2m:x:10340 + 1.0 + 1.0 + Multiple + Optional + + + Camera Name + R + Single + Mandatory + String + + + + + + + + Camera Status + R + Single + Mandatory + Boolean + + + + + + Connection Status + R + Single + Mandatory + Boolean + + + + + + Working Status + R + Single + Mandatory + Integer + 0..15 + + + + + Local Recording + R + Single + Mandatory + Boolean + + + + + + Image Matting + R + Single + Mandatory + Boolean + + + + + + Camera Snapshot + R + Single + Mandatory + Boolean + + + + + + Camera Recording + R + Single + Mandatory + Boolean + + + + + + + Camera Control + E + Single + Mandatory + + + + + + + Local Recording Control + E + Single + Mandatory + + + + + + + Image Matting Control + E + Single + Mandatory + + + + + + + Camera Snapshot Control + E + Single + Mandatory + + + + + + + Camera Recording Control + E + Single + Mandatory + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10341.xml b/transport/lwm2m/src/main/data/models/10341.xml new file mode 100644 index 0000000000..48b9c8a9e5 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10341.xml @@ -0,0 +1,70 @@ + + + + + GPS + + 10341 + urn:oma:lwm2m:x:10341 + 1.0 + 1.0 + Single + Optional + + + Host Device Unique ID + R + Single + Optional + String + + + + + + + + Host Device Manufacturer + R + Single + Optional + String + + + + + + + + Host Device Model Number + R + Single + Optional + String + + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10342.xml b/transport/lwm2m/src/main/data/models/10342.xml new file mode 100644 index 0000000000..3e1e950c9e --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10342.xml @@ -0,0 +1,70 @@ + + + + + IMU + + 10342 + urn:oma:lwm2m:x:10342 + 1.0 + 1.0 + Single + Optional + + + Host Device Unique ID + R + Single + Optional + String + + + + + + + + Host Device Manufacturer + R + Single + Optional + String + + + + + + + + Host Device Model Number + R + Single + Optional + String + + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10343.xml b/transport/lwm2m/src/main/data/models/10343.xml new file mode 100644 index 0000000000..273a7a38c3 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10343.xml @@ -0,0 +1,82 @@ + + + + + LiDAR + + 10343 + urn:oma:lwm2m:x:10343 + 1.0 + 1.0 + Multiple + Optional + + + LiDAR Name + R + Single + Mandatory + String + + + + + + + + Host Device Unique ID + R + Single + Optional + String + + + + + + + + Host Device Manufacturer + R + Single + Optional + String + + + + + + + + Host Device Model Number + R + Single + Optional + String + + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10344.xml b/transport/lwm2m/src/main/data/models/10344.xml new file mode 100644 index 0000000000..915372ad6a --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10344.xml @@ -0,0 +1,82 @@ + + + + + Arm + + 10344 + urn:oma:lwm2m:x:10344 + 1.0 + 1.0 + Multiple + Optional + + + Arm Name + R + Single + Mandatory + String + + + + + + + + Host Device Unique ID + R + Single + Optional + String + + + + + + + + Host Device Manufacturer + R + Single + Optional + String + + + + + + + + Host Device Model Number + R + Single + Optional + String + + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10345.xml b/transport/lwm2m/src/main/data/models/10345.xml new file mode 100644 index 0000000000..bd133a441f --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10345.xml @@ -0,0 +1,82 @@ + + + + + Leg + + 10345 + urn:oma:lwm2m:x:10345 + 1.0 + 1.0 + Multiple + Optional + + + Leg Name + R + Single + Mandatory + String + + + + + + + + Host Device Unique ID + R + Single + Optional + String + + + + + + + + Host Device Manufacturer + R + Single + Optional + String + + + + + + + + Host Device Model Number + R + Single + Optional + String + + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10346.xml b/transport/lwm2m/src/main/data/models/10346.xml new file mode 100644 index 0000000000..7e861471ac --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10346.xml @@ -0,0 +1,82 @@ + + + + + Servomotor + + 10346 + urn:oma:lwm2m:x:10346 + 1.0 + 1.0 + Multiple + Optional + + + Servomotor Name + R + Single + Mandatory + String + + + + + + + + Host Device Unique ID + R + Single + Optional + String + + + + + + + + Host Device Manufacturer + R + Single + Optional + String + + + + + + + + Host Device Model Number + R + Single + Optional + String + + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10347.xml b/transport/lwm2m/src/main/data/models/10347.xml new file mode 100644 index 0000000000..9c0bdf1aa0 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10347.xml @@ -0,0 +1,140 @@ + + + + + Screen + + 10347 + urn:oma:lwm2m:x:10347 + 1.0 + 1.0 + Single + Optional + + + Screen Status + R + Single + Mandatory + Boolean + + + + + + Startup Page + R + Single + Optional + String + + + The Startup Page of the screen. + + + Current Displaying Page or Current Screen Play List + R + Single + Optional + String + + + Current Displaying Page or Current Screen Play List. + + + + Screen Control + E + Single + Mandatory + + + + + + + Startup Page Set + E + Single + Mandatory + + + + + + + Screen Page Set + E + Single + Mandatory + + + + + + + Screen Play List Set + E + Single + Mandatory + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10348.xml b/transport/lwm2m/src/main/data/models/10348.xml new file mode 100644 index 0000000000..e06d17da3b --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10348.xml @@ -0,0 +1,82 @@ + + + + + Wheel + + 10348 + urn:oma:lwm2m:x:10348 + 1.0 + 1.0 + Multiple + Optional + + + Wheel Name + R + Single + Mandatory + String + + + + + + + + Host Device Unique ID + R + Single + Optional + String + + + + + + + + Host Device Manufacturer + R + Single + Optional + String + + + + + + + + Host Device Model Number + R + Single + Optional + String + + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10349.xml b/transport/lwm2m/src/main/data/models/10349.xml new file mode 100644 index 0000000000..dae4a6a9cb --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10349.xml @@ -0,0 +1,70 @@ + + + + + Chassis + + 10349 + urn:oma:lwm2m:x:10349 + 1.0 + 1.0 + Single + Optional + + + Host Device Unique ID + R + Single + Optional + String + + + + + + + + Host Device Manufacturer + R + Single + Optional + String + + + + + + + + Host Device Model Number + R + Single + Optional + String + + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10350.xml b/transport/lwm2m/src/main/data/models/10350.xml new file mode 100644 index 0000000000..6b822be2d6 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10350.xml @@ -0,0 +1,102 @@ + + + + + Light + + 10350 + urn:oma:lwm2m:x:10350 + 1.0 + 1.0 + Multiple + Optional + + + Light Name + R + Single + Mandatory + String + + + + + + + + Light Status + R + Single + Mandatory + Boolean + + + + + + + Light Control + E + Single + Mandatory + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10351.xml b/transport/lwm2m/src/main/data/models/10351.xml new file mode 100644 index 0000000000..379fa6c581 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10351.xml @@ -0,0 +1,65 @@ + + + + + Door + + 10351 + urn:oma:lwm2m:x:10351 + 1.0 + 1.0 + Multiple + Optional + + + Door Name + R + Single + Mandatory + String + + + + + + + Door Status + R + Single + Mandatory + Boolean + + + + + + + Door Control + E + Single + Mandatory + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10352.xml b/transport/lwm2m/src/main/data/models/10352.xml new file mode 100644 index 0000000000..ddd9907b3f --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10352.xml @@ -0,0 +1,100 @@ + + + + + Thermal Imager + + 10352 + urn:oma:lwm2m:x:10352 + 1.0 + 1.0 + Single + Optional + + + + Highest Temperature + R + Single + Mandatory + Float + -100.0..100.0 + Cel + The Highest Temperature of the thermal imager. + + + Lowest Temperature + R + Single + Mandatory + Float + -100.0..100.0 + Cel + The Lowest Temperature of the thermal imager. + + + Average Temperature + R + Single + Mandatory + Float + -100.0..100.0 + Cel + The Average Temperature of the thermal imager. + + + + + diff --git a/transport/lwm2m/src/main/data/models/10353.xml b/transport/lwm2m/src/main/data/models/10353.xml new file mode 100644 index 0000000000..dcb0fa534b --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10353.xml @@ -0,0 +1,73 @@ + + + + + Warning Light + + 10353 + urn:oma:lwm2m:x:10353 + 1.0 + 1.0 + Single + Optional + + + Light Status + R + Single + Mandatory + Boolean + + + + + + Light Warning + R + Single + Mandatory + Boolean + + + + + + Light Control + E + Single + Mandatory + + + + + + + Light Warning Control + E + Single + Mandatory + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10354.xml b/transport/lwm2m/src/main/data/models/10354.xml new file mode 100644 index 0000000000..f1faa3b18b --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10354.xml @@ -0,0 +1,203 @@ + + + + + APP + + 10354 + urn:oma:lwm2m:x:10354 + 1.0 + 1.0 + Multiple + Mandatory + + + APP Name + RW + Single + Mandatory + String + + + The name of the APP, human readable string. + + + APP Version + RW + Single + Mandatory + String + + + The version of the APP, human readable string. + + + APP Build No + RW + Single + Optional + String + + + The Build No of the APP, human readable string. + + + APP Patch No + RW + Single + Optional + String + + + The Patch No of the APP, human readable string. + + + Package URI + W + Single + Optional + String + 0-255 bytes + + + + + Vendor Name + RW + Single + Optional + String + + + The vendor of the package. + + + Installation Target + RW + Single + Mandatory + Objlnk + + + + + + APP Status + R + Single + Mandatory + Integer + 0..5 + + The Status of the APP, 0:Downloading, 1:Downloaded, 2:Installed, 3:Verified, 4:Activated, 5:Stopped. + + + APP Restart + E + Single + Mandatory + + + + + + + APP Start + E + Single + Mandatory + + + + + + + APP Stop + E + Single + Mandatory + + + + + + + APP Download + E + Single + Mandatory + + + + + + + APP Install + E + Single + Mandatory + + + + + + + APP Uninstall + E + Single + Mandatory + + + + + + + APP Activate + E + Single + Mandatory + + + + + + + APP Deactivate + E + Single + Mandatory + + + + + + + APP Verify + E + Single + Mandatory + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10355.xml b/transport/lwm2m/src/main/data/models/10355.xml new file mode 100644 index 0000000000..e485bd488a --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10355.xml @@ -0,0 +1,81 @@ + + + + + General Info + + 10355 + urn:oma:lwm2m:x:10355 + 1.0 + 1.0 + Single + Optional + + + Robot General Info + R + Single + Mandatory + Objlnk + + + + + + + + RCU General Info + R + Single + Mandatory + Objlnk + + + + + + + + CCU General Info + R + Multiple + Optional + Objlnk + + + + + + + + ECU General Info + R + Multiple + Optional + Objlnk + + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10356.xml b/transport/lwm2m/src/main/data/models/10356.xml new file mode 100644 index 0000000000..2de0ff6741 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10356.xml @@ -0,0 +1,189 @@ + + + + + Service Info + + 10356 + urn:oma:lwm2m:x:10356 + 1.0 + 1.0 + Single + Optional + + + Robot Service Info + R + Single + Mandatory + Objlnk + + + + + + + + SCA Info + R + Multiple + Optional + Objlnk + + + + + + + + Speaker Info + R + Single + Optional + Objlnk + + + + + + + + Camera Info + R + Multiple + Optional + Objlnk + + + + + + + + Screen Info + R + Single + Optional + Objlnk + + + + + + + + Light Info + R + Multiple + Optional + Objlnk + + + + + + + + Warning Light Info + R + Single + Optional + Objlnk + + + + + + + + Door Info + R + Multiple + Optional + Objlnk + + + + + + + + Thermal Imager Info + R + Single + Optional + Objlnk + + + + + + + + Compressor Info + R + Multiple + Optional + Objlnk + + + + + + + + Lock Info + R + Multiple + Optional + Objlnk + + + + + + + + Collision Sensor Info + R + Multiple + Optional + Objlnk + + + + + + + + Drop Sensor Info + R + Multiple + Optional + Objlnk + + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10357.xml b/transport/lwm2m/src/main/data/models/10357.xml new file mode 100644 index 0000000000..dec2d805ce --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10357.xml @@ -0,0 +1,81 @@ + + + + + PM + + 10357 + urn:oma:lwm2m:x:10357 + 1.0 + 1.0 + Single + Optional + + + Robot PM + R + Single + Mandatory + Objlnk + + + + + + + + RCU PM + R + Single + Mandatory + Objlnk + + + + + + + + CCU PM + R + Multiple + Optional + Objlnk + + + + + + + + SCA PM + R + Multiple + Optional + Objlnk + + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10358.xml b/transport/lwm2m/src/main/data/models/10358.xml new file mode 100644 index 0000000000..4be63ea09b --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10358.xml @@ -0,0 +1,56 @@ + + + + + Fan PM + + 10358 + urn:oma:lwm2m:x:10358 + 1.0 + 1.0 + Multiple + Optional + + + Fan Name + R + Single + Mandatory + String + + + + + + + + + Fan Speed + R + Single + Optional + Integer + + 1/min + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10359.xml b/transport/lwm2m/src/main/data/models/10359.xml new file mode 100644 index 0000000000..7f11ffa2e9 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10359.xml @@ -0,0 +1,64 @@ + + + + + Lock + + 10359 + urn:oma:lwm2m:x:10359 + 1.0 + 1.0 + Multiple + Optional + + + Lock Name + R + Single + Mandatory + String + + + + + + Lock Status + R + Single + Optional + Boolean + + + + + + + Lock Control + E + Single + Mandatory + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10360.xml b/transport/lwm2m/src/main/data/models/10360.xml new file mode 100644 index 0000000000..6908c5c80d --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10360.xml @@ -0,0 +1,56 @@ + + + + + Ultrasonic Sensor + + 10360 + urn:oma:lwm2m:x:10360 + 1.0 + 1.0 + Multiple + Optional + + + Name + R + Single + Mandatory + String + + + + + + + + + Status + R + Single + Mandatory + Integer + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10361.xml b/transport/lwm2m/src/main/data/models/10361.xml new file mode 100644 index 0000000000..1821406a8b --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10361.xml @@ -0,0 +1,78 @@ + + + + + Collision Sensor + + 10361 + urn:oma:lwm2m:x:10361 + 1.0 + 1.0 + Multiple + Optional + + + Name + R + Single + Mandatory + String + + + + + + + + Status + R + Single + Mandatory + Integer + + + + + + + Collision Detection + R + Single + Optional + Boolean + + + + + + + Collision Detection Control + E + Single + Mandatory + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10362.xml b/transport/lwm2m/src/main/data/models/10362.xml new file mode 100644 index 0000000000..2def77cd12 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10362.xml @@ -0,0 +1,77 @@ + + + + + Drop Sensor + + 10362 + urn:oma:lwm2m:x:10362 + 1.0 + 1.0 + Multiple + Optional + + + Name + R + Single + Mandatory + String + + + + + + + + Status + R + Single + Mandatory + Integer + + + + + + Drop Detection + R + Single + Optional + Boolean + + + + + + + Drop Detection Control + E + Single + Mandatory + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10363.xml b/transport/lwm2m/src/main/data/models/10363.xml new file mode 100644 index 0000000000..b34b54ccfe --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10363.xml @@ -0,0 +1,43 @@ + + + + + Temperature Sensor + + 10363 + urn:oma:lwm2m:x:10363 + 1.0 + 1.0 + Single + Optional + + + Status + R + Single + Mandatory + Integer + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10364.xml b/transport/lwm2m/src/main/data/models/10364.xml new file mode 100644 index 0000000000..09b64e24ad --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10364.xml @@ -0,0 +1,43 @@ + + + + + Humidity Sensor + + 10364 + urn:oma:lwm2m:x:10364 + 1.0 + 1.0 + Single + Optional + + + Status + R + Single + Mandatory + Integer + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10365.xml b/transport/lwm2m/src/main/data/models/10365.xml new file mode 100644 index 0000000000..6f5e3bb37b --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10365.xml @@ -0,0 +1,43 @@ + + + + + Gas-Dust Sensor + + 10365 + urn:oma:lwm2m:x:10365 + 1.0 + 1.0 + Single + Optional + + + Status + R + Single + Mandatory + Integer + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10366.xml b/transport/lwm2m/src/main/data/models/10366.xml new file mode 100644 index 0000000000..be603eeaee --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10366.xml @@ -0,0 +1,45 @@ + + + + + Fan + + 10366 + urn:oma:lwm2m:x:10366 + 1.0 + 1.0 + Multiple + Optional + + + Fan Name + R + Single + Mandatory + String + + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10368.xml b/transport/lwm2m/src/main/data/models/10368.xml new file mode 100644 index 0000000000..694219f23d --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10368.xml @@ -0,0 +1,82 @@ + + + + + SpringMotor + + 10368 + urn:oma:lwm2m:x:10368 + 1.0 + 1.0 + Multiple + Optional + + + SpringMotor Name + R + Single + Mandatory + String + + + + + + + + Host Device Unique ID + R + Single + Optional + String + + + + + + + + Host Device Manufacturer + R + Single + Optional + String + + + + + + + + Host Device Model Number + R + Single + Optional + String + + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/10369.xml b/transport/lwm2m/src/main/data/models/10369.xml new file mode 100644 index 0000000000..7f86a4a33a --- /dev/null +++ b/transport/lwm2m/src/main/data/models/10369.xml @@ -0,0 +1,70 @@ + + + + + MCU + + 10369 + urn:oma:lwm2m:x:10369 + 1.0 + 1.0 + Single + Optional + + + Host Device Unique ID + R + Single + Optional + String + + + + + + + + Host Device Manufacturer + R + Single + Optional + String + + + + + + + + Host Device Model Number + R + Single + Optional + String + + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/2048.xml b/transport/lwm2m/src/main/data/models/2048.xml new file mode 100644 index 0000000000..5dc5c7ebaf --- /dev/null +++ b/transport/lwm2m/src/main/data/models/2048.xml @@ -0,0 +1,75 @@ + + + + + CmdhPolicy + + 2048 + urn:oma:lwm2m:ext:20481.0 + 1.0Multiple + Optional + + Name + RW + Single + Mandatory + String + + + + + DefaultRule + RW + Single + Mandatory + Objlnk + + + + + LimiRules + RW + Multiple + Mandatory + Objlnk + + + + + NetworkAccessECRules + RW + Multiple + Mandatory + Objlnk + + + + + BufferRules + RW + Multiple + Mandatory + Objlnk + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/2049.xml b/transport/lwm2m/src/main/data/models/2049.xml new file mode 100644 index 0000000000..600e437189 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/2049.xml @@ -0,0 +1,44 @@ + + + + + ActiveCmdhPolicy + + 2049 + urn:oma:lwm2m:ext:20491.0 + 1.0Single + Optional + + ActiveLink + RW + Single + Mandatory + Objlnk + + + + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/2050.xml b/transport/lwm2m/src/main/data/models/2050.xml new file mode 100644 index 0000000000..caef96ef00 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/2050.xml @@ -0,0 +1,49 @@ + + + + + CmdhDefaults + + 2050 + urn:oma:lwm2m:ext:20501.0 + 1.0Multiple + Optional + + DefaultEcRules + RW + Multiple + Mandatory + Objlnk + + + + + + DefaultEcParamRules + RW + Multiple + Mandatory + Objlnk + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/2051.xml b/transport/lwm2m/src/main/data/models/2051.xml new file mode 100644 index 0000000000..828cfb809b --- /dev/null +++ b/transport/lwm2m/src/main/data/models/2051.xml @@ -0,0 +1,84 @@ + + + + + CmdhDefEcValues + + 2051 + urn:oma:lwm2m:ext:20511.0 + 1.0Multiple + Optional + + Order + RW + Single + Mandatory + Integer + + + + + DefEcValue + RW + Single + Mandatory + String + + + + + RequestOrigin + RW + Multiple + Mandatory + String + + + + + RequestContext + RW + Single + Optional + String + + + + + RequestContextNotification + RW + Single + Optional + Boolean + + + + + RequestCharacteristics + RW + Single + Optional + String + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/2052.xml b/transport/lwm2m/src/main/data/models/2052.xml new file mode 100644 index 0000000000..eccdac1d77 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/2052.xml @@ -0,0 +1,96 @@ + + + + + CmdhEcDefParamValues + + 2052 + urn:oma:lwm2m:ext:20521.0 + 1.0Multiple + Optional + + ApplicableEventCategory + RW + Multiple + Mandatory + Integer + + + + + DefaultRequestExpTime + RW + Single + Mandatory + Integer + + ms + + + + + + + + + DefaultResultExpTime + RW + Single + Mandatory + Integer + + ms + + + + DefaultOpExecTime + RW + Single + Mandatory + Integer + + ms + + + DefaultRespPersistence + RW + Single + Mandatory + Integer + + ms + + + DefaultDelAggregation + RW + Single + Mandatory + Integer + + ms + + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/2053.xml b/transport/lwm2m/src/main/data/models/2053.xml new file mode 100644 index 0000000000..6e822a4f82 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/2053.xml @@ -0,0 +1,150 @@ + + + + + CmdhLimits + + 2053 + urn:oma:lwm2m:ext:20531.0 + 1.0Multiple + Optional + + Order + RW + Single + Mandatory + Integer + + + + + RequestOrigin + RW + Multiple + Mandatory + String + + + + + + + + + + + RequestContext + RW + Single + Optional + String + + + + + + RequestContextNotificatio + RW + Single + Optional + Boolean + + + + + RequestCharacteristics + RW + Single + Optional + String + + + + + LimitsEventCategory + RW + Multiple + Mandatory + Integer + + + + + LimitsRequestExpTime + RW + Multiple + Mandatory + Integer + 2 Instances + ms + + + LimitsResultExpTime + RW + Multiple + Mandatory + Integer + 2 Instances + ms + + + LimitsOptExpTime + RW + Multiple + Mandatory + Integer + 2 Instances + ms + + + LimitsRespPersistence + RW + Multiple + Mandatory + Integer + 2 Instances + ms + + + LimitsDelAggregation + RW + Multiple + Mandatory + String + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/2054.xml b/transport/lwm2m/src/main/data/models/2054.xml new file mode 100644 index 0000000000..c99c16991c --- /dev/null +++ b/transport/lwm2m/src/main/data/models/2054.xml @@ -0,0 +1,54 @@ + + + + + CmdhNetworkAccessRules + + 2054 + urn:oma:lwm2m:ext:20541.0 + 1.0Multiple + Optional + + ApplicableEventCategories + RW + Multiple + Mandatory + Integer + + + + + NetworkAccessRule + RW + Multiple + Optional + Objlnk + + + + + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/2055.xml b/transport/lwm2m/src/main/data/models/2055.xml new file mode 100644 index 0000000000..f847b64c29 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/2055.xml @@ -0,0 +1,85 @@ + + + + + CmdhNwAccessRule + + 2055 + urn:oma:lwm2m:ext:20551.0 + 1.0Multiple + Optional + + TargetNetwork + RW + Multiple + Mandatory + String + + + + + SpreadingWaitTime + RW + Single + Mandatory + Integer + + ms + + + MinReqVolume + RW + Single + Mandatory + Integer + + B + + + BackOffParameters + RW + Single + Mandatory + Objlnk + + + + + OtherConditions + RW + Single + Mandatory + String + + + + + AllowedSchedule + RW + Multiple + Mandatory + String + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/2056.xml b/transport/lwm2m/src/main/data/models/2056.xml new file mode 100644 index 0000000000..5f643093f5 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/2056.xml @@ -0,0 +1,62 @@ + + + + + CmdhBuffer + + 2056 + urn:oma:lwm2m:ext:20561.0 + 1.0Multiple + Optional + + ApplicableEventCategory + RW + Multiple + Mandatory + Integer + + + + + MaxBufferSize + RW + Single + Mandatory + Integer + + B + + + StoragePriority + RW + Single + Mandatory + Integer + 1..10 + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/2057.xml b/transport/lwm2m/src/main/data/models/2057.xml new file mode 100644 index 0000000000..5ac9c96519 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/2057.xml @@ -0,0 +1,77 @@ + + + + + CmdhBackOffParametersSet + + 2057 + urn:oma:lwm2m:ext:2057 + 1.0 + 1.0 + Multiple + Optional + + NetworkAction + RW + Single + Optional + Integer + 1..5 + + + + InitialBackoffTime + RW + Single + Mandatory + Integer + + ms + + + AdditionalBackoffTime + RW + Single + Mandatory + Integer + + ms + + + MaximumBackoffTime + RW + Single + Mandatory + Integer + + ms + + + OptionalRandomBackoffTime + RW + Multiple + Optional + Integer + + ms + + + + + diff --git a/transport/lwm2m/src/main/data/models/31024.xml b/transport/lwm2m/src/main/data/models/31024.xml new file mode 100644 index 0000000000..00d27c32f8 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/31024.xml @@ -0,0 +1,68 @@ + + + + + Test + A Wakaama object for testing purpose. + + 31024 + urn:oma:lwm2m:x:31024 + Multiple + Optional + + + test + RW + Single + Mandatory + Integer + 0-255 + + + + exec + E + Single + Mandatory + + + + dec + RW + Single + Mandatory + Float + + + + + + sig + RW + Single + Optional + Integer + + + 16-bit signed integer + + + + + diff --git a/transport/lwm2m/src/main/data/models/3200.xml b/transport/lwm2m/src/main/data/models/3200.xml new file mode 100644 index 0000000000..9e1a994efc --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3200.xml @@ -0,0 +1,114 @@ + + + + + + Digital Input + Generic digital input for non-specific sensors + 3200 + urn:oma:lwm2m:ext:3200 + 1.0 + 1.0 + Multiple + Optional + + + Digital Input State + R + Single + Mandatory + Boolean + + + The current state of a digital input. + + + Digital Input Counter + R + Single + Optional + Integer + + + The cumulative value of active state detected. + + + Digital Input Polarity + RW + Single + Optional + Boolean + + + The polarity of the digital input as a Boolean (False = Normal, True = Reversed). + + + Digital Input Debounce + RW + Single + Optional + Integer + + ms + The debounce period in ms. + + + Digital Input Edge Selection + RW + Single + Optional + Integer + 1..3 + + The edge selection as an integer (1 = Falling edge, 2 = Rising edge, 3 = Both Rising and Falling edge). + + + Digital Input Counter Reset + E + Single + Optional + + + + Reset the Counter value. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string, for instance, "Air Pressure" + + + Sensor Type + R + Single + Optional + String + + + The type of the sensor (for instance PIR type) + + + + + diff --git a/transport/lwm2m/src/main/data/models/3201.xml b/transport/lwm2m/src/main/data/models/3201.xml new file mode 100644 index 0000000000..32484c8be1 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3201.xml @@ -0,0 +1,63 @@ + + + + + Digital Output + Generic digital output for non-specific actuators + 3201 + urn:oma:lwm2m:ext:3201 + 1.0 + 1.0 + Multiple + Optional + + + Digital Output State + RW + Single + Mandatory + Boolean + + + The current state of a digital output. + + + Digital Output Polarity + RW + Single + Optional + Boolean + + + The polarity of the digital output as a Boolean (False = Normal, True = Reversed). + + + Application Type + RW + Single + Optional + String + + + The application type of the output as a string, for instance, "LED" + + + + + diff --git a/transport/lwm2m/src/main/data/models/3202.xml b/transport/lwm2m/src/main/data/models/3202.xml new file mode 100644 index 0000000000..391abb5a0f --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3202.xml @@ -0,0 +1,113 @@ + + + + + Analog Input + Generic analog input for non-specific sensors + 3202 + urn:oma:lwm2m:ext:3202 + 1.0 + 1.0 + Multiple + Optional + + + Analog Input Current Value + R + Single + Mandatory + Float + + + The current value of the analog input. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string, for instance, "Air Pressure" + + + Sensor Type + R + Single + Optional + String + + + The type of the sensor, for instance PIR type + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + + + diff --git a/transport/lwm2m/src/main/data/models/3203.xml b/transport/lwm2m/src/main/data/models/3203.xml new file mode 100644 index 0000000000..4dd1ae8c40 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3203.xml @@ -0,0 +1,73 @@ + + + + + Analog Output + This IPSO object is a generic object that can be used with any kind of analog output interface. + 3203 + urn:oma:lwm2m:ext:3203 + 1.0 + 1.0 + Multiple + Optional + + + Analog Output Current Value + RW + Single + Mandatory + Float + 0..1 + + The current state of the analogue output. + + + Application Type + RW + Single + Optional + String + + + If present, the application type of the actuator as a string, for instance, "Valve" + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be set for the output + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be set for the output + + + + + diff --git a/transport/lwm2m/src/main/data/models/3300.xml b/transport/lwm2m/src/main/data/models/3300.xml new file mode 100644 index 0000000000..20ab00a0d3 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3300.xml @@ -0,0 +1,123 @@ + + + + + Generic Sensor + This IPSO object allows the description of a generic sensor. It is based on the description of a value and a unit according to the SenML specification. Thus, any type of value defined within this specification can be reported using this object. This object may be used as a generic object if a dedicated one does not exist. + 3300 + urn:oma:lwm2m:ext:3300 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Application Type + RW + Single + Optional + String + + + If present, the application type of the sensor as a string, for instance, "CO2" + + + Sensor Type + R + Single + Optional + String + + + The type of the sensor (for instance PIR type) + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + + + diff --git a/transport/lwm2m/src/main/data/models/3301.xml b/transport/lwm2m/src/main/data/models/3301.xml new file mode 100644 index 0000000000..923c7dc176 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3301.xml @@ -0,0 +1,103 @@ + + + + + Illuminance + Illuminance sensor, example units = lx + 3301 + urn:oma:lwm2m:ext:3301 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + The current value of the luminosity sensor. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + + + diff --git a/transport/lwm2m/src/main/data/models/3302.xml b/transport/lwm2m/src/main/data/models/3302.xml new file mode 100644 index 0000000000..ba49a72f5a --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3302.xml @@ -0,0 +1,93 @@ + + + + + Presence + Presence sensor with digital sensing, optional delay parameters + 3302 + urn:oma:lwm2m:ext:3302 + 1.0 + 1.0 + Multiple + Optional + + + Digital Input State + R + Single + Mandatory + Boolean + + + The current state of the presence sensor + + + Digital Input Counter + R + Single + Optional + Integer + + + The cumulative value of active state detected. + + + Digital Input Counter Reset + E + Single + Optional + + + + Reset the Counter value + + + Sensor Type + R + Single + Optional + String + + + The type of the sensor (for instance PIR type) + + + Busy to Clear delay + RW + Single + Optional + Integer + + ms + Delay from the detection state to the clear state in ms + + + Clear to Busy delay + RW + Single + Optional + Integer + + ms + Delay from the clear state to the busy state in ms + + + + + diff --git a/transport/lwm2m/src/main/data/models/3303.xml b/transport/lwm2m/src/main/data/models/3303.xml new file mode 100644 index 0000000000..b73e967135 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3303.xml @@ -0,0 +1,103 @@ + + + + + Temperature + This IPSO object should be used with a temperature sensor to report a temperature measurement. It also provides resources for minimum/maximum measured values and the minimum/maximum range that can be measured by the temperature sensor. An example measurement unit is degrees Celsius. + 3303 + urn:oma:lwm2m:ext:3303 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + + + diff --git a/transport/lwm2m/src/main/data/models/3304.xml b/transport/lwm2m/src/main/data/models/3304.xml new file mode 100644 index 0000000000..47b4361c96 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3304.xml @@ -0,0 +1,103 @@ + + + + + Humidity + This IPSO object should be used with a humidity sensor to report a humidity measurement. It also provides resources for minimum/maximum measured values and the minimum/maximum range that can be measured by the humidity sensor. An example measurement unit is relative humidity as a percentage. + 3304 + urn:oma:lwm2m:ext:3304 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + + + diff --git a/transport/lwm2m/src/main/data/models/3305.xml b/transport/lwm2m/src/main/data/models/3305.xml new file mode 100644 index 0000000000..314c6b6a8e --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3305.xml @@ -0,0 +1,213 @@ + + + + + Power Measurement + This IPSO object should be used over a power measurement sensor to report a remote power measurement. It also provides resources for minimum/maximum measured values and the minimum/maximum range for both active and reactive power. It also provides resources for cumulative energy, calibration, and the power factor. + 3305 + urn:oma:lwm2m:ext:3305 + 1.0 + 1.0 + Multiple + Optional + + + Instantaneous active power + R + Single + Mandatory + Float + + W + The current active power + + + Min Measured active power + R + Single + Optional + Float + + W + The minimum active power measured by the sensor since it is ON + + + Max Measured active power + R + Single + Optional + Float + + W + The maximum active power measured by the sensor since it is ON + + + Min Range active power + R + Single + Optional + Float + + W + The minimum active power that can be measured by the sensor + + + Max Range active power + R + Single + Optional + Float + + W + The maximum active power that can be measured by the sensor + + + Cumulative active power + R + Single + Optional + Float + + Wh + The cumulative active power since the last cumulative energy reset or device start + + + Active Power Calibration + W + Single + Optional + Float + + W + Request an active power calibration by writing the value of a calibrated load. + + + Instantaneous reactive power + R + Single + Optional + Float + + var + The current reactive power + + + Min Measured reactive power + R + Single + Optional + Float + + var + The minimum reactive power measured by the sensor since it is ON + + + Max Measured reactive power + R + Single + Optional + Float + + var + The maximum reactive power measured by the sensor since it is ON + + + Min Range reactive power + R + Single + Optional + Float + + var + The minimum active power that can be measured by the sensor + + + Max Range reactive power + R + Single + Optional + Float + + var + The maximum reactive power that can be measured by the sensor + + + Cumulative reactive power + R + Single + Optional + Float + + varh + The cumulative reactive power since the last cumulative energy reset or device start + + + Reactive Power Calibration + W + Single + Optional + Float + + var + Request a reactive power calibration by writing the value of a calibrated load. + + + Power factor + R + Single + Optional + Float + + + If applicable, the power factor of the current consumption. + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Reset Cumulative energy + E + Single + Optional + + + + Reset both cumulative active/reactive power + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + + + diff --git a/transport/lwm2m/src/main/data/models/3306.xml b/transport/lwm2m/src/main/data/models/3306.xml new file mode 100644 index 0000000000..a1534488c5 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3306.xml @@ -0,0 +1,83 @@ + + + + + Actuation + This IPSO object is dedicated to remote actuation such as ON/OFF action or dimming. A multi-state output can also be described as a string. This is useful to send pilot wire orders for instance. It also provides a resource to reflect the time that the device has been switched on. + 3306 + urn:oma:lwm2m:ext:3306 + 1.0 + 1.0 + Multiple + Optional + + + On/Off + RW + Single + Mandatory + Boolean + + + On/off control. Boolean value where True is On and False is Off. + + + Dimmer + RW + Single + Optional + Integer + 0..100 + /100 + This resource represents a light dimmer setting, which has an Integer value between 0 and 100 as a percentage. + + + On time + RW + Single + Optional + Integer + + s + The time in seconds that the device has been on. Writing a value of 0 resets the counter. + + + Muti-state Output + RW + Single + Optional + String + + + A string describing a state for multiple level output such as Pilot Wire + + + Application Type + RW + Single + Optional + String + + + The Application type of the device, for example "Motion Closure". + + + + + diff --git a/transport/lwm2m/src/main/data/models/3308.xml b/transport/lwm2m/src/main/data/models/3308.xml new file mode 100644 index 0000000000..021f172572 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3308.xml @@ -0,0 +1,73 @@ + + + + + Set Point + This IPSO object should be used to set a desired value to a controller, such as a thermostat. A special resource is added to set the colour of an object. + 3308 + urn:oma:lwm2m:ext:3308 + 1.0 + 1.0 + Multiple + Optional + + + Set Point Value + RW + Single + Mandatory + Float + + + The setpoint value. + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Colour + RW + Single + Optional + String + + + A string representing a value in some color space + + + Application Type + RW + Single + Optional + String + + + The Application type of the device, for example "Motion Closure". + + + + + diff --git a/transport/lwm2m/src/main/data/models/3310.xml b/transport/lwm2m/src/main/data/models/3310.xml new file mode 100644 index 0000000000..74408d45aa --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3310.xml @@ -0,0 +1,93 @@ + + + + + Load Control + This Object is used for demand-response load control and other load control in automation application (not limited to power). + 3310 + urn:oma:lwm2m:ext:3310 + 1.0 + 1.0 + Multiple + Optional + + + Event Identifier + RW + Single + Mandatory + String + + + The event identifier as a string. + + + Start Time + RW + Single + Mandatory + Time + + + Time when the event started. + + + Duration In Min + RW + Single + Mandatory + Integer + + min + The duration of the event in minutes. + + + Criticality Level + RW + Single + Optional + Integer + 0..3 + + The criticality of the event. The device receiving the event will react in an appropriate fashion for the device. + + + Avg Load AdjPct + RW + Single + Optional + Integer + 0..100 + /100 + Defines the maximum energy usage of the receiving device, as a percentage of the device's normal maximum energy usage. + + + Duty Cycle + RW + Single + Optional + Integer + 0..100 + /100 + Defines the duty cycle for the load control event, i.e, what percentage of time the receiving device is allowed to be on. + + + + + diff --git a/transport/lwm2m/src/main/data/models/3311.xml b/transport/lwm2m/src/main/data/models/3311.xml new file mode 100644 index 0000000000..e27543c055 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3311.xml @@ -0,0 +1,113 @@ + + + + + Light Control + This Object is used to control a light source, such as a LED or other light. It allows a light to be turned on or off and its dimmer setting to be control as a % between 0 and 100. An optional colour setting enables a string to be used to indicate the desired colour. + 3311 + urn:oma:lwm2m:ext:3311 + 1.0 + 1.0 + Multiple + Optional + + + On/Off + RW + Single + Mandatory + Boolean + + + On/off control. Boolean value where True is On and False is Off. + + + Dimmer + RW + Single + Optional + Integer + 0..100 + /100 + This resource represents a light dimmer setting, which has an Integer value between 0 and 100 as a percentage. + + + On time + RW + Single + Optional + Integer + + s + The time in seconds that the light has been on. Writing a value of 0 resets the counter. + + + Cumulative active power + R + Single + Optional + Float + + Wh + The total power in Wh that the light has used. + + + Power factor + R + Single + Optional + Float + + + The power factor of the light. + + + Colour + RW + Single + Optional + String + + + A string representing a value in some color space + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string, for instance, "Air Pressure" + + + + + diff --git a/transport/lwm2m/src/main/data/models/3312.xml b/transport/lwm2m/src/main/data/models/3312.xml new file mode 100644 index 0000000000..395db11213 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3312.xml @@ -0,0 +1,93 @@ + + + + + Power Control + This Object is used to control a power source, such as a Smart Plug. It allows a power relay to be turned on or off and its dimmer setting to be control as a % between 0 and 100. + 3312 + urn:oma:lwm2m:ext:3312 + 1.0 + 1.0 + Multiple + Optional + + + On/Off + RW + Single + Mandatory + Boolean + + + On/off control. Boolean value where True is On and False is Off. + + + Dimmer + RW + Single + Optional + Integer + 0..100 + /100 + This resource represents a power dimmer setting, which has an Integer value between 0 and 100 as a percentage. + + + On time + RW + Single + Optional + Integer + + s + The time in seconds that the power relay has been on. Writing a value of 0 resets the counter. + + + Cumulative active power + R + Single + Optional + Float + + Wh + The total power in Wh that has been used by the load. + + + Power factor + R + Single + Optional + Float + + + The power factor of the load. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string, for instance, "Air Pressure" + + + + + diff --git a/transport/lwm2m/src/main/data/models/3313.xml b/transport/lwm2m/src/main/data/models/3313.xml new file mode 100644 index 0000000000..6617d8eaa0 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3313.xml @@ -0,0 +1,93 @@ + + + + + Accelerometer + This IPSO object can be used to represent a 1-3 axis accelerometer. + 3313 + urn:oma:lwm2m:ext:3313 + 1.0 + 1.0 + Multiple + Optional + + + X Value + R + Single + Mandatory + Float + + + The measured value along the X axis. + + + Y Value + R + Single + Optional + Float + + + The measured value along the Y axis. + + + Z Value + R + Single + Optional + Float + + + The measured value along the Z axis. + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + + + diff --git a/transport/lwm2m/src/main/data/models/3314.xml b/transport/lwm2m/src/main/data/models/3314.xml new file mode 100644 index 0000000000..6c1379171c --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3314.xml @@ -0,0 +1,83 @@ + + + + + Magnetometer + This IPSO object can be used to represent a 1-3 axis magnetometer with optional compass direction. + 3314 + urn:oma:lwm2m:ext:3314 + 1.0 + 1.0 + Multiple + Optional + + + X Value + R + Single + Mandatory + Float + + + The measured value along the X axis. + + + Y Value + R + Single + Optional + Float + + + The measured value along the Y axis. + + + Z Value + R + Single + Optional + Float + + + The measured value along the Z axis. + + + Compass Direction + R + Single + Optional + Float + 0..360 + deg + The measured compass direction. + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + + + diff --git a/transport/lwm2m/src/main/data/models/3315.xml b/transport/lwm2m/src/main/data/models/3315.xml new file mode 100644 index 0000000000..61db630342 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3315.xml @@ -0,0 +1,103 @@ + + + + + Barometer + This IPSO object should be used with an air pressure sensor to report a barometer measurement. It also provides resources for minimum/maximum measured values and the minimum/maximum range that can be measured by the barometer sensor. An example measurement unit is pascals. + 3315 + urn:oma:lwm2m:ext:3315 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + + + diff --git a/transport/lwm2m/src/main/data/models/3316.xml b/transport/lwm2m/src/main/data/models/3316.xml new file mode 100644 index 0000000000..b7cd6fba52 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3316.xml @@ -0,0 +1,124 @@ + + + + + Voltage + This IPSO object should be used with voltmeter sensor to report measured voltage between two points. It also provides resources for minimum and maximum measured values, as well as the minimum and maximum range that can be measured by the sensor. An example measurement unit is volts. + + 3316 + urn:oma:lwm2m:ext:3316 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/transport/lwm2m/src/main/data/models/3317.xml b/transport/lwm2m/src/main/data/models/3317.xml new file mode 100644 index 0000000000..da57a69036 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3317.xml @@ -0,0 +1,124 @@ + + + + + Current + This IPSO object should be used with an ammeter to report measured electric current in amperes. It also provides resources for minimum and maximum measured values, as well as the minimum and maximum range that can be measured by the sensor. An example measurement unit is ampere. + + 3317 + urn:oma:lwm2m:ext:3317 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/transport/lwm2m/src/main/data/models/3318.xml b/transport/lwm2m/src/main/data/models/3318.xml new file mode 100644 index 0000000000..add0f7bd59 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3318.xml @@ -0,0 +1,124 @@ + + + + + Frequency + This IPSO object should be used to report frequency measurements. It also provides resources for minimum and maximum measured values, as well as the minimum and maximum range that can be measured by the sensor. An example measurement unit is hertz. + + 3318 + urn:oma:lwm2m:ext:3318 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/transport/lwm2m/src/main/data/models/3319.xml b/transport/lwm2m/src/main/data/models/3319.xml new file mode 100644 index 0000000000..dc23451a0c --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3319.xml @@ -0,0 +1,124 @@ + + + + + Depth + This IPSO object should be used to report depth measurements. It can, for example, be used to describe a generic rain gauge that measures the accumulated rainfall in millimetres (mm). + + 3319 + urn:oma:lwm2m:ext:3319 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/transport/lwm2m/src/main/data/models/3320.xml b/transport/lwm2m/src/main/data/models/3320.xml new file mode 100644 index 0000000000..17497bd3b0 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3320.xml @@ -0,0 +1,124 @@ + + + + + Percentage + This IPSO object should can be used to report measurements relative to a 0-100% scale. For example it could be used to measure the level of a liquid in a vessel or container in units of %. + + 3320 + urn:oma:lwm2m:ext:3320 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/transport/lwm2m/src/main/data/models/3321.xml b/transport/lwm2m/src/main/data/models/3321.xml new file mode 100644 index 0000000000..e53e749494 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3321.xml @@ -0,0 +1,124 @@ + + + + + Altitude + This IPSO object should be used with an altitude sensor to report altitude above sea level in meters. Note that Altitude can be calculated from the measured pressure given the local sea level pressure. It also provides resources for minimum and maximum measured values, as well as the minimum and maximum range that can be measured by the sensor. An example measurement unit is meters. + + 3321 + urn:oma:lwm2m:ext:3321 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/transport/lwm2m/src/main/data/models/3322.xml b/transport/lwm2m/src/main/data/models/3322.xml new file mode 100644 index 0000000000..cc87893761 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3322.xml @@ -0,0 +1,124 @@ + + + + + Load + This IPSO object should be used with a load sensor (as in a scale) to report the applied weight or force. It also provides resources for minimum and maximum measured values, as well as the minimum and maximum range that can be measured by the sensor. An example measurement unit is kilograms. + + 3322 + urn:oma:lwm2m:ext:3322 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/transport/lwm2m/src/main/data/models/3323.xml b/transport/lwm2m/src/main/data/models/3323.xml new file mode 100644 index 0000000000..ffe2991229 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3323.xml @@ -0,0 +1,124 @@ + + + + + Pressure + This IPSO object should be used to report pressure measurements. It also provides resources for minimum and maximum measured values, as well as the minimum and maximum range that can be measured by the sensor. An example measurement unit is pascals. + + 3323 + urn:oma:lwm2m:ext:3323 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/transport/lwm2m/src/main/data/models/3324.xml b/transport/lwm2m/src/main/data/models/3324.xml new file mode 100644 index 0000000000..f90fc40fa7 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3324.xml @@ -0,0 +1,124 @@ + + + + + Loudness + This IPSO object should be used to report loudness or noise level measurements. It also provides resources for minimum and maximum measured values, as well as the minimum and maximum range that can be measured by the sensor. An example measurement unit is decibels. + + 3324 + urn:oma:lwm2m:ext:3324 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/transport/lwm2m/src/main/data/models/3325.xml b/transport/lwm2m/src/main/data/models/3325.xml new file mode 100644 index 0000000000..68ffe881b9 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3325.xml @@ -0,0 +1,124 @@ + + + + + Concentration + This IPSO object should be used to the particle concentration measurement of a medium. It also provides resources for minimum and maximum measured values, as well as the minimum and maximum range that can be measured by the sensor. An example measurement unit is parts per million. + + 3325 + urn:oma:lwm2m:ext:3325 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/transport/lwm2m/src/main/data/models/3326.xml b/transport/lwm2m/src/main/data/models/3326.xml new file mode 100644 index 0000000000..66112b1792 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3326.xml @@ -0,0 +1,124 @@ + + + + + Acidity + This IPSO object should be used to report an acidity measurement of a liquid. It also provides resources for minimum and maximum measured values, as well as the minimum and maximum range that can be measured by the sensor. An example measurement unit is pH. + + 3326 + urn:oma:lwm2m:ext:3326 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/transport/lwm2m/src/main/data/models/3327.xml b/transport/lwm2m/src/main/data/models/3327.xml new file mode 100644 index 0000000000..e5087ecbb3 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3327.xml @@ -0,0 +1,124 @@ + + + + + Conductivity + This IPSO object should be used to report a measurement of the electric conductivity of a medium or sample. It also provides resources for minimum and maximum measured values, as well as the minimum and maximum range that can be measured by the sensor. An example measurement unit is Siemens. + + 3327 + urn:oma:lwm2m:ext:3327 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/transport/lwm2m/src/main/data/models/3328.xml b/transport/lwm2m/src/main/data/models/3328.xml new file mode 100644 index 0000000000..0eeb123c35 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3328.xml @@ -0,0 +1,124 @@ + + + + + Power + This IPSO object should be used to report power measurements. It also provides resources for minimum and maximum measured values, as well as the minimum and maximum range that can be measured by the sensor. An example measurement unit is Watts. This object may be used for either real power or apparent power measurements. + + 3328 + urn:oma:lwm2m:ext:3328 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/transport/lwm2m/src/main/data/models/3329.xml b/transport/lwm2m/src/main/data/models/3329.xml new file mode 100644 index 0000000000..ccfc356119 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3329.xml @@ -0,0 +1,124 @@ + + + + + Power Factor + This IPSO object should be used to report a measurement or calculation of the power factor of a reactive electrical load. Power Factor is normally the ratio of non-reactive power to total power. This object also provides resources for minimum and maximum measured values, as well as the minimum and maximum range that can be measured by the sensor. + + 3329 + urn:oma:lwm2m:ext:3329 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/transport/lwm2m/src/main/data/models/3330.xml b/transport/lwm2m/src/main/data/models/3330.xml new file mode 100644 index 0000000000..a9ca035a01 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3330.xml @@ -0,0 +1,124 @@ + + + + + Distance + This IPSO object should be used to report a distance measurement. It also provides resources for minimum and maximum measured values, as well as the minimum and maximum range that can be measured by the sensor. An example measurement unit is Meters. + + 3330 + urn:oma:lwm2m:ext:3330 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/transport/lwm2m/src/main/data/models/3331.xml b/transport/lwm2m/src/main/data/models/3331.xml new file mode 100644 index 0000000000..2da640e45f --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3331.xml @@ -0,0 +1,74 @@ + + + + + Energy + This IPSO object should be used to report energy consumption (Cumulative Power) of an electrical load. An example measurement unit is Watt Hours. + + 3331 + urn:oma:lwm2m:ext:3331 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor. + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Reset Cumulative energy + E + Single + Optional + + + + Reset both cumulative active/reactive power. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/transport/lwm2m/src/main/data/models/3332.xml b/transport/lwm2m/src/main/data/models/3332.xml new file mode 100644 index 0000000000..26755629a7 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3332.xml @@ -0,0 +1,84 @@ + + + + + Direction + This IPSO object is used to report the direction indicated by a compass, wind vane, or other directional indicator. The units of measure is plane angle degrees. + + 3332 + urn:oma:lwm2m:ext:3332 + 1.0 + 1.0 + Multiple + Optional + + + Compass Direction + R + Single + Mandatory + Float + 0..360 + deg + The measured compass direction. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset. + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset. + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/transport/lwm2m/src/main/data/models/3333.xml b/transport/lwm2m/src/main/data/models/3333.xml new file mode 100644 index 0000000000..62a574f68e --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3333.xml @@ -0,0 +1,64 @@ + + + + + Time + This IPSO object is used to report the current time in seconds since January 1, 1970 UTC. There is also a fractional time counter that has a range of less than one second. + + 3333 + urn:oma:lwm2m:ext:3333 + 1.0 + 1.0 + Multiple + Optional + + + Current Time + RW + Single + Mandatory + Time + + + Unix Time. A signed integer representing the number of seconds since Jan 1st, 1970 in the UTC time zone. + + + Fractional Time + RW + Single + Optional + Float + 0..1 + s + Fractional part of the time when sub-second precision is used (e.g., 0.23 for 230 ms). + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/transport/lwm2m/src/main/data/models/3334.xml b/transport/lwm2m/src/main/data/models/3334.xml new file mode 100644 index 0000000000..e72ec20cc3 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3334.xml @@ -0,0 +1,174 @@ + + + + + Gyrometer + This IPSO Object is used to report the current reading of a gyrometer sensor in 3 axes. It provides tracking of the minimum and maximum angular rate in all 3 axes. An example unit of measure is radians per second. + + 3334 + urn:oma:lwm2m:ext:3334 + 1.0 + 1.0 + Multiple + Optional + + + X Value + R + Single + Mandatory + Float + + + The measured value along the X axis. + + + Y Value + R + Single + Optional + Float + + + The measured value along the Y axis. + + + Z Value + R + Single + Optional + Float + + + The measured value along the Z axis. + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min X Value + R + Single + Optional + Float + + + The minimum measured value along the X axis + + + Max X Value + R + Single + Optional + Float + + + The maximum measured value along the X axis + + + Min Y Value + R + Single + Optional + Float + + + The minimum measured value along the Y axis + + + Max Y Value + R + Single + Optional + Float + + + The maximum measured value along the Y axis + + + Min Z Value + R + Single + Optional + Float + + + The minimum measured value along the Z axis + + + Max Z Value + R + Single + Optional + Float + + + The maximum measured value along the Z axis + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value. + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/transport/lwm2m/src/main/data/models/3335.xml b/transport/lwm2m/src/main/data/models/3335.xml new file mode 100644 index 0000000000..789c5d33a3 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3335.xml @@ -0,0 +1,64 @@ + + + + + Colour + This IPSO object should be used to report the measured value of a colour sensor in some colour space described by the units resource. + + 3335 + urn:oma:lwm2m:ext:3335 + 1.0 + 1.0 + Multiple + Optional + + + Colour + RW + Single + Mandatory + String + + + A string representing a value in some colour space. + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/transport/lwm2m/src/main/data/models/3336.xml b/transport/lwm2m/src/main/data/models/3336.xml new file mode 100644 index 0000000000..5172c63156 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3336.xml @@ -0,0 +1,104 @@ + + + + + Location + This IPSO object represents GPS coordinates. This object is compatible with the LWM2M management object for location, but uses reusable resources. + + 3336 + urn:oma:lwm2m:ext:3336 + 1.0 + 1.0 + Multiple + Optional + + + Latitude + R + Single + Mandatory + String + + + The decimal notation of latitude, e.g. -43.5723 (World Geodetic System 1984). + + + Longitude + R + Single + Mandatory + String + + + The decimal notation of longitude, e.g. 153.21760 (World Geodetic System 1984). + + + Uncertainty + R + Single + Optional + String + + + The accuracy of the position in meters. + + + Compass Direction + R + Single + Optional + Float + 0..360 + deg + The measured compass direction. + + + Velocity + R + Single + Optional + Opaque + + + The velocity of the device as defined in 3GPP 23.032 GAD specification. This set of values may not be available if the device is static. + + + Timestamp + R + Single + Optional + Time + + + The timestamp of when the measurement was performed. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/transport/lwm2m/src/main/data/models/3337.xml b/transport/lwm2m/src/main/data/models/3337.xml new file mode 100644 index 0000000000..50abbe1621 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3337.xml @@ -0,0 +1,124 @@ + + + + + Positioner + This IPSO object should be used with a generic position actuator with range from 0 to 100%. This object optionally allows setting the transition time for an operation that changes the position of the actuator, and for reading the remaining time of the currently active transition. + + 3337 + urn:oma:lwm2m:ext:3337 + 1.0 + 1.0 + Multiple + Optional + + + Current Position + RW + Single + Mandatory + Float + 0..100 + /100 + Current position or desired position of a positioner actuator. + + + Transition Time + RW + Single + Optional + Float + + s + The time expected to move the actuator to the new position. + + + Remaining Time + R + Single + Optional + Float + + s + The time remaining in an operation. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value set on the actuator since power ON or reset. + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value set on the actuator since power ON or reset. + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value. + + + Min Limit + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor. + + + Max Limit + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/transport/lwm2m/src/main/data/models/3338.xml b/transport/lwm2m/src/main/data/models/3338.xml new file mode 100644 index 0000000000..cfa1062a81 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3338.xml @@ -0,0 +1,84 @@ + + + + + Buzzer + This IPSO object should be used to actuate an audible alarm such as a buzzer, beeper, or vibration alarm. There is a dimmer control for setting the relative loudness of the alarm, and an optional duration control to limit the length of time the alarm sounds when turned on. Each time "true" is written to the On/Off resource, the alarm will sound again for the configured duration. If no duration is programmed or the setting is "false", writing a "true" to the On/Off resource will result in the alarm sounding continuously until a "false" is written to the On/Off resource. + + 3338 + urn:oma:lwm2m:ext:3338 + 1.0 + 1.0 + Multiple + Optional + + + On/Off + RW + Single + Mandatory + Boolean + + + On/off control. Boolean value where True is On and False is Off. + + + Level + RW + Single + Optional + Float + 0..100 + /100 + Audio volume control, float value between 0 and 100 as a percentage. + + + Delay Duration + RW + Single + Optional + Float + + s + The duration of the time delay. + + + Minimum Off-time + RW + Single + Mandatory + Float + + s + The off time when On/Off control remains on. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/transport/lwm2m/src/main/data/models/3339.xml b/transport/lwm2m/src/main/data/models/3339.xml new file mode 100644 index 0000000000..461b14c160 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3339.xml @@ -0,0 +1,83 @@ + + + + + Audio Clip + This IPSO object should be used for a speaker that plays a pre-recorded audio clip or an audio output that is sent elsewhere. For example, an elevator which announces the floor of the building. A resource is provided to store the clip, a dimmer resource controls the relative sound level of the playback, and a duration resource limits the maximum playback time. After the duration time is reached, any remaining samples in the clip are ignored, and the clip player will be ready to play another clip. + 3339 + urn:oma:lwm2m:ext:3339 + 1.0 + 1.0 + Multiple + Optional + + + Clip + RW + Single + Mandatory + Opaque + + + Audio clip that is playable (e.g., a short audio recording indicating the floor in an elevator). + + + Trigger + E + Single + Optional + + + + Trigger initiating actuation. + + + Level + RW + Single + Optional + Float + 0..100 + /100 + Audio volume control, float value between 0 and 100 as a percentage. + + + Duration + RW + Single + Optional + Float + + s + The duration of the sound once trigger. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/transport/lwm2m/src/main/data/models/3340.xml b/transport/lwm2m/src/main/data/models/3340.xml new file mode 100644 index 0000000000..035b7e5bac --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3340.xml @@ -0,0 +1,144 @@ + + + + + Timer + This IPSO object is used to time events and actions, using patterns common to industrial timers. A write to the trigger resource or On/Off input state change starts the timing operation, and the timer remaining time shows zero when the operation is complete. The patterns supported are One-Shot (mode 1), On-Time or Interval (mode 2), Time delay on pick-up or TDPU (mode 3), and Time Delay on Drop-Out or TDDO (mode 4). Mode 0 disables the timer, so the output follows the input with no delay. A counter is provided to count occurrences of the timer output changing from 0 to 1. Writing a value of zero resets the counter. The Digital Input State resource reports the state of the timer output. + + 3340 + urn:oma:lwm2m:ext:3340 + 1.0 + 1.0 + Multiple + Optional + + + Delay Duration + RW + Single + Mandatory + Float + + s + The duration of the time delay. + + + Remaining Time + R + Single + Optional + Float + + s + The time remaining in an operation. + + + Minimum Off-time + RW + Single + Optional + Float + + s + The duration of the rearm delay (i.e. the delay from the end of one cycle until the beginning of the next, the inhibit time). + + + Trigger + E + Single + Optional + + + + Trigger initiating actuation. + + + On/Off + RW + Single + Optional + Boolean + + + On/off control. Boolean value where True is On and False is Off. + + + Digital Input Counter + R + Single + Optional + Integer + + + The number of times the input. + + + Cumulative Time + RW + Single + Optional + Float + + s + The total time in seconds that the timer input is true. Writing a 0 resets the time. + + + Digital State + R + Single + Optional + Boolean + + + The current state of the timer output. + + + Counter + RW + Single + Optional + Integer + + + Counts the number of times the timer output transitions from 0 to 1. + + + Timer Mode + RW + Single + Optional + Integer + 0..4 + + Type of timer pattern used by the patterns. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/transport/lwm2m/src/main/data/models/3341.xml b/transport/lwm2m/src/main/data/models/3341.xml new file mode 100644 index 0000000000..ba22001e9a --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3341.xml @@ -0,0 +1,124 @@ + + + + + Addressable Text Display + This IPSO object is used to send text to a text-only or text mode graphics display. Writing a string of text to the text resource causes it to be displayed at the selected X and Y locations on the display. If X or Y are set to a value greater than the size of the display, the position "wraps around" to the modulus of the setting and the display size. Likewise, if the text string overflows the display size, the text "wraps around" and displays on the next line down or, if the last line has been written, wraps around to the top of the display. Brightness and Contrast controls are provided to allow control of various display types including STN and DSTN type LCD character displays. Writing an empty payload to the Clear Display resource causes the display to be erased. + + 3341 + urn:oma:lwm2m:ext:3341 + 1.0 + 1.0 + Multiple + Optional + + + Text + RW + Single + Mandatory + String + + + A string of text. + + + X Coordinate + RW + Single + Optional + Integer + + + X Coordinate. + + + Y Coordinate + RW + Single + Optional + Integer + + + Y Coordinate. + + + Max X Coordinate + R + Single + Optional + Integer + + + The highest X coordinate the display supports before wrapping to the next line. + + + Max Y Coordinate + R + Single + Optional + Integer + + + The highest Y coordinate the display supports before wrapping to the next line. + + + Clear Display + E + Single + Optional + + + + Command to clear the display. + + + Level + RW + Single + Optional + Float + 0..100 + /100 + Brightness control, integer value between 0 and 100 as a percentage. + + + Contrast + RW + Single + Optional + Float + 0..100 + /100 + Proportional control, integer value between 0 and 100 as a percentage. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/transport/lwm2m/src/main/data/models/3342.xml b/transport/lwm2m/src/main/data/models/3342.xml new file mode 100644 index 0000000000..30797468d5 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3342.xml @@ -0,0 +1,83 @@ + + + + + On/Off switch + This IPSO object should be used with an On/Off switch to report the state of the switch. + 3342 + urn:oma:lwm2m:ext:3342 + 1.0 + 1.0 + Multiple + Optional + + + Digital Input State + R + Single + Mandatory + Boolean + + + The current state of a digital input. + + + Digital Input Counter + R + Single + Optional + Integer + + + The number of times the input transitions from 0 to 1. + + + On time + RW + Single + Optional + Integer + + s + The time in seconds since the On command was sent. Writing a value of 0 resets the counter. + + + Off Time + RW + Single + Optional + Integer + + s + The time in seconds since the Off command was sent. Writing a value of 0 resets the counter. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/transport/lwm2m/src/main/data/models/3343.xml b/transport/lwm2m/src/main/data/models/3343.xml new file mode 100644 index 0000000000..2a1ead53cb --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3343.xml @@ -0,0 +1,74 @@ + + + + + Dimmer + This IPSO object should be used with a dimmer or level control to report the state of the control. + + 3343 + urn:oma:lwm2m:ext:3343 + 1.0 + 1.0 + Multiple + Optional + + + Level + RW + Single + Mandatory + Float + 0..100 + /100 + Proportional control, integer value between 0 and 100 as a percentage. + + + On time + RW + Single + Optional + Integer + + s + The time in seconds that the dimmer has been on (Dimmer value has to be > 0). Writing a value of 0 resets the counter. + + + Off Time + RW + Single + Optional + Integer + + s + The time in seconds that the dimmer has been off (dimmer value less or equal to 0) Writing a value of 0 resets the counter. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/transport/lwm2m/src/main/data/models/3344.xml b/transport/lwm2m/src/main/data/models/3344.xml new file mode 100644 index 0000000000..d6f3335a6e --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3344.xml @@ -0,0 +1,84 @@ + + + + + Up/Down Control + This IPSO object is used to report the state of an up/down control element like a pair of push buttons or a rotary encoder. Counters for increase and decrease operations are provided for counting pulses from a quadrature encoder. + + 3344 + urn:oma:lwm2m:ext:3344 + 1.0 + 1.0 + Multiple + Optional + + + Increase Input State + R + Single + Mandatory + Boolean + + + Indicates an increase control action. + + + Decrease Input State + R + Single + Mandatory + Boolean + + + Indicates a decrease control action. + + + Up Counter + RW + Single + Optional + Integer + + + Counts the number of times the increase control has been operated. Writing a 0 resets the counter. + + + Down Counter + RW + Single + Optional + Integer + + + Counts the times the decrease control has been operated. Writing a 0 resets the counter. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/transport/lwm2m/src/main/data/models/3345.xml b/transport/lwm2m/src/main/data/models/3345.xml new file mode 100644 index 0000000000..acf780488f --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3345.xml @@ -0,0 +1,94 @@ + + + + + Multiple Axis Joystick + This IPSO object can be used to report the position of a shuttle or joystick control. A digital input is provided to report the state of an associated push button. + + 3345 + urn:oma:lwm2m:ext:3345 + 1.0 + 1.0 + Multiple + Optional + + + Digital Input State + R + Single + Optional + Boolean + + + The current state of a digital input. + + + Digital Input Counter + R + Single + Optional + Integer + + + The number of times the input transitions from 0 to 1. + + + X Value + R + Single + Optional + Float + + + The measured value along the X axis. + + + Y Value + R + Single + Optional + Float + + + The measured value along the Y axis. + + + Z Value + R + Single + Optional + Float + + + The measured value along the Z axis. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/transport/lwm2m/src/main/data/models/3346.xml b/transport/lwm2m/src/main/data/models/3346.xml new file mode 100644 index 0000000000..edca22adf4 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3346.xml @@ -0,0 +1,124 @@ + + + + + Rate + This object type should be used to report a rate measurement, for example the speed of a vehicle, or the rotational speed of a drive shaft. It also provides resources for minimum and maximum measured values, as well as the minimum and maximum range that can be measured by the sensor. An example measurement unit is meters per second (m/s). + + 3346 + urn:oma:lwm2m:ext:3346 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + Current Calibration + RW + Single + Optional + Float + + + Read or Write the current calibration coefficient + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case + + + + + diff --git a/transport/lwm2m/src/main/data/models/3347.xml b/transport/lwm2m/src/main/data/models/3347.xml new file mode 100644 index 0000000000..38355dcd82 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3347.xml @@ -0,0 +1,64 @@ + + + + + Push button + This IPSO object is used to report the state of a momentary action push button control and to count the number of times the control has been operated since the last observation. + + 3347 + urn:oma:lwm2m:ext:3347 + 1.0 + 1.0 + Multiple + Optional + + + Digital Input State + R + Single + Mandatory + Boolean + + + The current state of a digital input. + + + Digital Input Counter + R + Single + Optional + Integer + + + The number of times the input transitions from 0 to 1. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/transport/lwm2m/src/main/data/models/3348.xml b/transport/lwm2m/src/main/data/models/3348.xml new file mode 100644 index 0000000000..bed7ac56d8 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3348.xml @@ -0,0 +1,54 @@ + + + + + Multi-state Selector + This IPSO object is used to represent the state of a Multi-state selector switch with a number of fixed positions. + + 3348 + urn:oma:lwm2m:ext:3348 + 1.0 + 1.0 + Multiple + Optional + + + Multi-state Input + R + Single + Mandatory + Integer + + + The current state of a Multi-state input or selector. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/transport/lwm2m/src/main/data/models/3349.xml b/transport/lwm2m/src/main/data/models/3349.xml new file mode 100644 index 0000000000..8f96334ef2 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3349.xml @@ -0,0 +1,73 @@ + + + + + Bitmap + Summarize several digital inputs to one value by mapping each bit to a digital input. + 3349 + urn:oma:lwm2m:ext:3349 + 1.0 + 1.0 + Multiple + Optional + + + Bitmap Input + R + Single + Mandatory + Integer + + + Integer in which each of the bits are associated with specific digital input value. Represented as a binary signed integer in network byte order, and in two's complement representation. Using values in range 0-127 is recommended to avoid ambiguities with byte order and negative values. + + + Bitmap Input Reset + E + Single + Optional + + + + Reset the Bitmap Input value. + + + Element Description + RW + Multiple + Optional + String + + + The description of each bit as a string. First instance describes the least significant bit, second instance the second least significant bit. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/transport/lwm2m/src/main/data/models/3350.xml b/transport/lwm2m/src/main/data/models/3350.xml new file mode 100644 index 0000000000..8f026d846a --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3350.xml @@ -0,0 +1,73 @@ + + + + + Stopwatch + An ascending timer that counts how long time has passed since the timer was started after reset. + 3350 + urn:oma:lwm2m:ext:3350 + 1.0 + 1.0 + Multiple + Optional + + + Cumulative Time + RW + Single + Mandatory + Float + + s + The total time in seconds that the stopwatch has been on. Writing a 0 resets the time. + + + On/Off + RW + Single + Optional + Boolean + + + On/off control. Boolean value where True is On and False is Off. + + + Digital Input Counter + R + Single + Optional + Integer + + + The number of times the input transitions from off to on. + + + Application Type + RW + Single + Optional + String + + + The application type of the sensor or actuator as a string depending on the use case. + + + + + diff --git a/transport/lwm2m/src/main/data/models/3351.xml b/transport/lwm2m/src/main/data/models/3351.xml new file mode 100644 index 0000000000..c39b18c9fb --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3351.xml @@ -0,0 +1,148 @@ + + + + powerupLog + + 3351 + urn:oma:lwm2m:ext:3351 + 1.0 + 1.0 + Single + Optional + + deviceName + R + Single + Mandatory + String + + + + + toolVersion + R + Single + Mandatory + String + + + + + IMEI + R + Single + Mandatory + String + + + + + IMSI + R + Single + Mandatory + String + + + + + MSISDN + R + Single + Mandatory + String + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3352.xml b/transport/lwm2m/src/main/data/models/3352.xml new file mode 100644 index 0000000000..1d00dcd95c --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3352.xml @@ -0,0 +1,141 @@ + + + + plmnSearchEvent + + 3352 + urn:oma:lwm2m:ext:3352 + 1.0 + 1.0 + Multiple + Optional + + timeScanStart + R + Single + Mandatory + Integer + + + + + plmnID + R + Single + Mandatory + Integer + + + + + BandIndicator + R + Single + Mandatory + Integer + + + + + dlEarfcn + R + Single + Mandatory + Integer + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3353.xml b/transport/lwm2m/src/main/data/models/3353.xml new file mode 100644 index 0000000000..f57fa2de1d --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3353.xml @@ -0,0 +1,140 @@ + + + + scellID + + 3353 + urn:oma:lwm2m:ext:3353 + 1.0 + 1.0 + Single + Optional + + plmnID + R + Single + Mandatory + Integer + + + + + BandIndicator + R + Single + Mandatory + Integer + + + + + TrackingAreaCode + R + Single + Mandatory + Integer + + + + + CellID + R + Single + Mandatory + Integer + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3354.xml b/transport/lwm2m/src/main/data/models/3354.xml new file mode 100644 index 0000000000..2f70b5668d --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3354.xml @@ -0,0 +1,151 @@ + + + + cellReselectionEvent + + 3354 + urn:oma:lwm2m:ext:3354 + 1.0 + 1.0 + Single + Optional + + timeReselectionStart + R + Single + Mandatory + Integer + + + + + dlEarfcn + R + Single + Mandatory + Integer + + + + + CellID + R + Single + Mandatory + Integer + + + + + failureType + R + Single + Mandatory + Integer + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3355.xml b/transport/lwm2m/src/main/data/models/3355.xml new file mode 100644 index 0000000000..6387566c67 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3355.xml @@ -0,0 +1,173 @@ + + + + handoverEvent + + 3355 + urn:oma:lwm2m:ext:3355 + 1.0 + 1.0 + Single + Optional + + timeHandoverStart + R + Single + Mandatory + Integer + + + + + dlEarfcn + R + Single + Mandatory + Integer + + + + + CellID + R + Single + Mandatory + Integer + + + + + handoverResult + R + Single + Mandatory + Integer + + + + + + TargetEarfcn + R + Single + Mandatory + Integer + + + + + TargetPhysicalCellID + R + Single + Mandatory + Integer + + + + + targetCellRsrp + R + Single + Mandatory + Integer + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3356.xml b/transport/lwm2m/src/main/data/models/3356.xml new file mode 100644 index 0000000000..2c585903bb --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3356.xml @@ -0,0 +1,137 @@ + + + + radioLinkFailureEvent + + 3356 + urn:oma:lwm2m:ext:3356 + 1.0 + 1.0 + Single + Optional + + timeRLF + R + Single + Mandatory + Integer + + + + + rlfCause + R + Single + Mandatory + Integer + + + + + + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3357.xml b/transport/lwm2m/src/main/data/models/3357.xml new file mode 100644 index 0000000000..9d03cbdc7c --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3357.xml @@ -0,0 +1,148 @@ + + + + rrcStateChangeEvent + + 3357 + urn:oma:lwm2m:ext:3357 + 1.0 + 1.0 + Single + Optional + + rrcState + R + Single + Mandatory + Integer + + + + + rrcStateChangeCause + R + Single + Mandatory + Integer + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3358.xml b/transport/lwm2m/src/main/data/models/3358.xml new file mode 100644 index 0000000000..45775cd0fa --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3358.xml @@ -0,0 +1,123 @@ + + + + rrcTimerExpiryEvent + + 3358 + urn:oma:lwm2m:ext:3358 + 1.0 + 1.0 + Single + Optional + + RrcTimerExpiryEvent + R + Single + Mandatory + Integer + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3359.xml b/transport/lwm2m/src/main/data/models/3359.xml new file mode 100644 index 0000000000..d623ecedda --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3359.xml @@ -0,0 +1,122 @@ + + + + cellBlacklistEvent + + 3359 + urn:oma:lwm2m:ext:3359 + 1.0 + 1.0 + Single + Optional + + dlEarfcn + R + Single + Mandatory + Integer + + + + + CellID + R + Single + Mandatory + Integer + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3360.xml b/transport/lwm2m/src/main/data/models/3360.xml new file mode 100644 index 0000000000..9995ab133e --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3360.xml @@ -0,0 +1,145 @@ + + + + esmContextInfo + + 3360 + urn:oma:lwm2m:ext:3360 + 1.0 + 1.0 + Single + Optional + + contextType + R + Single + Mandatory + Integer + + + + + bearerState + R + Single + Mandatory + Integer + + + + + radioBearerId + R + Single + Mandatory + Integer + + + + + qci + R + Single + Mandatory + Integer + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3361.xml b/transport/lwm2m/src/main/data/models/3361.xml new file mode 100644 index 0000000000..6660583208 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3361.xml @@ -0,0 +1,147 @@ + + + + emmStateValue + + 3361 + urn:oma:lwm2m:ext:3361 + 1.0 + 1.0 + Single + Optional + + EmmState + R + Single + Mandatory + Integer + + + + + emmSubstate + R + Single + Mandatory + Integer + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3362.xml b/transport/lwm2m/src/main/data/models/3362.xml new file mode 100644 index 0000000000..a9b3de3e5a --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3362.xml @@ -0,0 +1,114 @@ + + + + nasEmmTimerExpiryEvent + + 3362 + urn:oma:lwm2m:ext:3362 + 1.0 + 1.0 + Single + Optional + + NasEmmTimerExpiryEvent + R + Single + Mandatory + Integer + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3363.xml b/transport/lwm2m/src/main/data/models/3363.xml new file mode 100644 index 0000000000..b040474dc2 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3363.xml @@ -0,0 +1,117 @@ + + + + nasEsmExpiryEvent + + 3363 + urn:oma:lwm2m:ext:3363 + 1.0 + 1.0 + Single + Optional + + NasEsmExpiryEvent + R + Single + Mandatory + Integer + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3364.xml b/transport/lwm2m/src/main/data/models/3364.xml new file mode 100644 index 0000000000..18bdd00f5a --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3364.xml @@ -0,0 +1,114 @@ + + + + emmFailureCauseEvent + + 3364 + urn:oma:lwm2m:ext:3364 + 1.0 + 1.0 + Single + Optional + + EMMCause + R + Single + Mandatory + Integer + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3365.xml b/transport/lwm2m/src/main/data/models/3365.xml new file mode 100644 index 0000000000..385d952809 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3365.xml @@ -0,0 +1,140 @@ + + + + rachLatency_delay + + 3365 + urn:oma:lwm2m:ext:3365 + 1.0 + 1.0 + Single + Optional + + sysFrameNumber + R + Single + Mandatory + Integer + + + + + subFrameNumber + R + Single + Mandatory + Integer + + + + + rachLatencyVal + R + Single + Mandatory + Integer + + + + + delay + R + Single + Mandatory + Integer + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3366.xml b/transport/lwm2m/src/main/data/models/3366.xml new file mode 100644 index 0000000000..150c5b84b6 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3366.xml @@ -0,0 +1,193 @@ + + + + macRachAttemptEvent + + 3366 + urn:oma:lwm2m:ext:3366 + 1.0 + 1.0 + Single + Optional + + rachAttemptCounter + R + Single + Mandatory + Integer + + + + + MacRachAttemptEventType + R + Single + Mandatory + Integer + + + + + contentionBased + R + Single + Mandatory + Boolean + + + + + rachMessage + R + Single + Mandatory + Integer + + + + + preambleIndex + R + Single + Mandatory + Integer + + + + + preamblePowerOffset + R + Single + Mandatory + Integer + + + + + backoffTime + R + Single + Mandatory + Integer + + + + + msg2Result + R + Single + Mandatory + Boolean + + + + + timingAdjustmentValue + R + Single + Mandatory + Integer + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3367.xml b/transport/lwm2m/src/main/data/models/3367.xml new file mode 100644 index 0000000000..fc0ac146e0 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3367.xml @@ -0,0 +1,155 @@ + + + + macRachAttemptReasonEvent + + 3367 + urn:oma:lwm2m:ext:3367 + 1.0 + 1.0 + Single + Optional + + MacRachAttemptReasonType + R + Single + Mandatory + Integer + + + + + ueID + R + Single + Mandatory + Integer + + + + + contentionBased + R + Single + Mandatory + Boolean + + + + + preamble + R + Single + Mandatory + Integer + + + + + preambleGroupChosen + R + Single + Mandatory + Boolean + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3368.xml b/transport/lwm2m/src/main/data/models/3368.xml new file mode 100644 index 0000000000..2f877024d6 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3368.xml @@ -0,0 +1,117 @@ + + + + macTimerStatusEvent + + 3368 + urn:oma:lwm2m:ext:3368 + 1.0 + 1.0 + Single + Optional + + macTimerName + R + Single + Mandatory + Integer + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3369.xml b/transport/lwm2m/src/main/data/models/3369.xml new file mode 100644 index 0000000000..72debece44 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3369.xml @@ -0,0 +1,122 @@ + + + + macTimingAdvanceEvent + + 3369 + urn:oma:lwm2m:ext:3369 + 1.0 + 1.0 + Single + Optional + + timerValue + R + Single + Mandatory + Integer + + + + + timingAdvance + R + Single + Mandatory + Integer + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3370.xml b/transport/lwm2m/src/main/data/models/3370.xml new file mode 100644 index 0000000000..93df78c63f --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3370.xml @@ -0,0 +1,158 @@ + + + + ServingCellMeasurement + + 3370 + urn:oma:lwm2m:ext:3370 + 1.0 + 1.0 + Single + Optional + + sysFrameNumber + R + Single + Mandatory + Integer + + + + + subFrameNumber + R + Single + Mandatory + Integer + + + + + pci + R + Single + Mandatory + Integer + + + + + rsrp + R + Single + Mandatory + Integer + + + + + rsrq + R + Single + Mandatory + Integer + + + + + dlEarfcn + R + Single + Mandatory + Integer + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3371.xml b/transport/lwm2m/src/main/data/models/3371.xml new file mode 100644 index 0000000000..e61288f414 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3371.xml @@ -0,0 +1,158 @@ + + + + NeighborCellMeasurements + + 3371 + urn:oma:lwm2m:ext:3371 + 1.0 + 1.0 + Multiple + Optional + + sysFrameNumber + R + Single + Mandatory + Integer + + + + + subFrameNumber + R + Single + Mandatory + Integer + + + + + pci + R + Single + Mandatory + Integer + + + + + rsrp + R + Single + Mandatory + Integer + + + + + rsrq + R + Single + Mandatory + Integer + + + + + dlEarfcn + R + Single + Mandatory + Integer + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3372.xml b/transport/lwm2m/src/main/data/models/3372.xml new file mode 100644 index 0000000000..959cccf917 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3372.xml @@ -0,0 +1,132 @@ + + + + TimingAdvance + + 3372 + urn:oma:lwm2m:ext:3372 + 1.0 + 1.0 + Single + Optional + + sysFrameNumber + R + Single + Mandatory + Integer + + + + + subFrameNumber + R + Single + Mandatory + Integer + + + + + timingAdvance + R + Single + Mandatory + Integer + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3373.xml b/transport/lwm2m/src/main/data/models/3373.xml new file mode 100644 index 0000000000..b932370393 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3373.xml @@ -0,0 +1,132 @@ + + + + txPowerHeadroomEvent + + 3373 + urn:oma:lwm2m:ext:3373 + 1.0 + 1.0 + Single + Optional + + sysFrameNumber + R + Single + Mandatory + Integer + + + + + subFrameNumber + R + Single + Mandatory + Integer + + + + + headroom-value + R + Single + Mandatory + Integer + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3374.xml b/transport/lwm2m/src/main/data/models/3374.xml new file mode 100644 index 0000000000..ca04397c8d --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3374.xml @@ -0,0 +1,149 @@ + + + + radioLinkMonitoring + + 3374 + urn:oma:lwm2m:ext:3374 + 1.0 + 1.0 + Single + Optional + + sysFrameNumber + R + Single + Mandatory + Integer + + + + + subFrameNumber + R + Single + Mandatory + Integer + + + + + outOfSyncCount + R + Single + Mandatory + Integer + + + + + inSyncCount + R + Single + Mandatory + Integer + + + + + t310Timer + R + Single + Mandatory + Boolean + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3375.xml b/transport/lwm2m/src/main/data/models/3375.xml new file mode 100644 index 0000000000..9d0e12eb3c --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3375.xml @@ -0,0 +1,167 @@ + + + + PagingDRX + + 3375 + urn:oma:lwm2m:ext:3375 + 1.0 + 1.0 + Single + Optional + + dlEarfcn + R + Single + Mandatory + Integer + + + + + pci + R + Single + Mandatory + Integer + + + + + pagingCycle + R + Single + Mandatory + Integer + + + + + DrxNb + R + Single + Mandatory + Integer + + + + + ueID + R + Single + Mandatory + Integer + + + + + drxSysFrameNumOffset + R + Single + Mandatory + Integer + + + + + drxSubFrameNumOffset + R + Single + Mandatory + Integer + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3376.xml b/transport/lwm2m/src/main/data/models/3376.xml new file mode 100644 index 0000000000..91172c66e6 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3376.xml @@ -0,0 +1,114 @@ + + + + txPowerBackOffEvent + + 3376 + urn:oma:lwm2m:ext:3376 + 1.0 + 1.0 + Single + Optional + + TxPowerBackoff + R + Single + Mandatory + Integer + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3377.xml b/transport/lwm2m/src/main/data/models/3377.xml new file mode 100644 index 0000000000..28204ff2ce --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3377.xml @@ -0,0 +1,185 @@ + + + + Message3Report + + 3377 + urn:oma:lwm2m:ext:3377 + 1.0 + 1.0 + Single + Optional + + tpc + R + Single + Mandatory + Integer + + + + + resourceIndicatorValue + R + Single + Mandatory + Integer + + + + + cqi + R + Single + Mandatory + Integer + + + + + uplinkDelay + R + Single + Mandatory + Boolean + + + + + hoppingEnabled + R + Single + Mandatory + Boolean + + + + + numRb + R + Single + Mandatory + Integer + + + + + transportBlockSizeIndex + R + Single + Mandatory + Integer + + + + + ModulationType + R + Single + Mandatory + Integer + + + + + redundancyVersionIndex + R + Single + Mandatory + Integer + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3378.xml b/transport/lwm2m/src/main/data/models/3378.xml new file mode 100644 index 0000000000..a9c1ebc45d --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3378.xml @@ -0,0 +1,132 @@ + + + + PbchDecodingResults + + 3378 + urn:oma:lwm2m:ext:3378 + 1.0 + 1.0 + Single + Optional + + servingCellID + R + Single + Mandatory + Integer + + + + + crcResult + R + Single + Mandatory + Boolean + + + + + sysFrameNumber + R + Single + Mandatory + Integer + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3379.xml b/transport/lwm2m/src/main/data/models/3379.xml new file mode 100644 index 0000000000..2a684f2ddd --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3379.xml @@ -0,0 +1,140 @@ + + + + pucchPowerControl + + 3379 + urn:oma:lwm2m:ext:3379 + 1.0 + 1.0 + Single + Optional + + sysFrameNumber + R + Single + Mandatory + Integer + + + + + subFrameNumber + R + Single + Mandatory + Integer + + + + + pucchTxPowerValue + + Single + Mandatory + Integer + + + + + dlPathLoss + R + Single + Mandatory + Integer + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3380-2_0.xml b/transport/lwm2m/src/main/data/models/3380-2_0.xml new file mode 100644 index 0000000000..21f9eb9f50 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3380-2_0.xml @@ -0,0 +1,221 @@ + + + + PrachReport + + 3380 + urn:oma:lwm2m:ext:3380:2.0 + 1.0 + 2.0 + Single + Optional + + sysFrameNumber + R + Single + Mandatory + Integer + + + + + subFrameNumber + R + Single + Mandatory + Integer + + + + + rachTxPower + R + Single + Mandatory + Integer + + + + + zadOffSeqNum + R + Single + Mandatory + Integer + + + + + prachConfig + R + Single + Mandatory + Integer + + + + + preambleFormat + R + Single + Mandatory + Integer + + + + + maxTransmissionMsg3 + R + Single + Mandatory + Integer + + + + + raResponseWindowSize + R + Single + Mandatory + Integer + + + + + RachRequestResult + R + Single + Mandatory + Boolean + + + + + ce_mode + R + Single + Mandatory + Integer + + + + + ce_level + R + Single + Mandatory + Integer + + + + + num_prach_repetition + R + Single + Mandatory + Integer + + + + + prach_repetition_seq + R + Single + Mandatory + Integer + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3381.xml b/transport/lwm2m/src/main/data/models/3381.xml new file mode 100644 index 0000000000..9df2e862b9 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3381.xml @@ -0,0 +1,127 @@ + + + + VolteCallEvent + + 3381 + urn:oma:lwm2m:ext:3381 + 1.0 + 1.0 + Single + Optional + + callStatus + R + Single + Mandatory + Integer + + + + + callType + R + Single + Mandatory + Integer + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3382.xml b/transport/lwm2m/src/main/data/models/3382.xml new file mode 100644 index 0000000000..774a3ad20c --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3382.xml @@ -0,0 +1,125 @@ + + + + SipRegistrationEvent + + 3382 + urn:oma:lwm2m:ext:3382 + 1.0 + 1.0 + Single + Optional + + registrationType + R + Single + Mandatory + Integer + + + + + registrationResult + R + Single + Mandatory + Integer + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3383.xml b/transport/lwm2m/src/main/data/models/3383.xml new file mode 100644 index 0000000000..2bd5ed9c24 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3383.xml @@ -0,0 +1,116 @@ + + + + sipPublishEvent + + 3383 + urn:oma:lwm2m:ext:3383 + 1.0 + 1.0 + Single + Optional + + publishResult + R + Single + Mandatory + Integer + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3384.xml b/transport/lwm2m/src/main/data/models/3384.xml new file mode 100644 index 0000000000..53cdb71c85 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3384.xml @@ -0,0 +1,129 @@ + + + + sipSubscriptionEvent + + 3384 + urn:oma:lwm2m:ext:3384 + 1.0 + 1.0 + Single + Optional + + eventType + R + Single + Mandatory + Integer + + + + + subscriptionResult + R + Single + Mandatory + Integer + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3385.xml b/transport/lwm2m/src/main/data/models/3385.xml new file mode 100644 index 0000000000..bf73c6ec9c --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3385.xml @@ -0,0 +1,127 @@ + + + + volteCallStateChangeEvent + + 3385 + urn:oma:lwm2m:ext:3385 + 1.0 + 1.0 + Single + Optional + + callStatus + R + Single + Mandatory + Integer + + + + + VolteCallStateChangeCause + R + Single + Mandatory + Integer + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/3386.xml b/transport/lwm2m/src/main/data/models/3386.xml new file mode 100644 index 0000000000..64b7ab7ece --- /dev/null +++ b/transport/lwm2m/src/main/data/models/3386.xml @@ -0,0 +1,122 @@ + + + + VoLTErtpPacketLoss + 1]]> + 3386 + urn:oma:lwm2m:ext:3386 + 1.0 + 1.0 + Single + Optional + + ssrc + R + Single + Mandatory + Integer + + + + + packetsLost + R + Single + Mandatory + Integer + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/LWM2M_APN_Connection_Profile-v1_0_1.xml b/transport/lwm2m/src/main/data/models/LWM2M_APN_Connection_Profile-v1_0_1.xml new file mode 100644 index 0000000000..c1bade6f62 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/LWM2M_APN_Connection_Profile-v1_0_1.xml @@ -0,0 +1,287 @@ + + + + + LWM2M APN Connection Profile + + 11 + + urn:oma:lwm2m:oma:11 + 1.0 + 1.0 + Multiple + Optional + + Profile name + RW + Single + Mandatory + String + + + + + APN + RW + Single + Optional + String + + + + + Auto select APN by device + RW + Single + Optional + Boolean + + + + + Enable status + RW + Single + Optional + Boolean + + + + + Authentication Type + RW + Single + Mandatory + Integer + + + + + User Name + RW + Single + Optional + String + + + + + Secret + RW + Single + Optional + String + + + + + Reconnect Schedule + RW + Single + Optional + String + + + + + Validity (MCC, MNC) + RW + Multiple + Optional + String + + + + + Connection establishment time (1) + R + Multiple + Optional + Time + + + + + Connection establishment result (1) + R + Multiple + Optional + Integer + + + + + + Connection establishment reject cause (1) + R + Multiple + Optional + Integer + 0..111 + + + + Connection end time (1) + R + Multiple + Optional + Time + + + + + TotalBytesSent + R + Single + Optional + Integer + + + + + TotalBytesReceived + R + Single + Optional + Integer + + + + + IP address (2) + RW + Multiple + Optional + String + + + + + Prefix length(2) + RW + Multiple + Optional + String + + + + + Subnet mask (2) + RW + Multiple + Optional + String + + + + + Gateway (2) + RW + Multiple + Optional + String + + + + + Primary DNS address (2) + RW + Multiple + Optional + String + + + + + Secondary DNS address (2) + RW + Multiple + Optional + String + + + + + QCI (3) + R + Single + Optional + Integer + 1..9 + + + + Vendor specific extensions + R + Single + Optional + Objlnk + + + + + TotalPacketsSent + R + Single + Optional + Integer + + + + + PDN Type + RW + Single + Optional + Integer + + + + + + APN Rate Control + R + Single + Optional + Integer + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/LWM2M_Bearer_Selection-v1_0_1.xml b/transport/lwm2m/src/main/data/models/LWM2M_Bearer_Selection-v1_0_1.xml new file mode 100644 index 0000000000..0e52c8b58e --- /dev/null +++ b/transport/lwm2m/src/main/data/models/LWM2M_Bearer_Selection-v1_0_1.xml @@ -0,0 +1,174 @@ + + + + + LWM2M Bearer Selection + + 13 + urn:oma:lwm2m:oma:13 + 1.0 + 1.0 + Single + Optional + + Preferred Communications Bearer + RW + Multiple + Optional + Integer + 8 bit + + + + Acceptable RSSI (GSM) + RW + Single + Optional + Integer + + + + + Acceptable RSCP (UMTS) + RW + Single + Optional + Integer + + + + + Acceptable RSRP (LTE) + RW + Single + Optional + Integer + + + + + Acceptable RSSI (1xEV-DO) + RW + Single + Optional + Integer + + + + + Cell lock list + RW + Single + Optional + String + + + + + Operator list + RW + Single + Optional + String + + + + + Operator list mode + RW + Single + Optional + Boolean + + + + + List of available PLMNs + R + Single + Optional + String + + + + + Vendor specific extensions + R + Single + Optional + Objlnk + + + + + Acceptable RSRP (NB-IoT) + RW + Single + Optional + Integer + + + + + Higher Priority PLMN Search Timer + RW + Single + Optional + Integer + + + + + Attach without PDN connection + RW + Single + Optional + Boolean + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/LWM2M_Cellular_Connectivity-v1_0_1.xml b/transport/lwm2m/src/main/data/models/LWM2M_Cellular_Connectivity-v1_0_1.xml new file mode 100644 index 0000000000..b02490cc6d --- /dev/null +++ b/transport/lwm2m/src/main/data/models/LWM2M_Cellular_Connectivity-v1_0_1.xml @@ -0,0 +1,146 @@ + + + + + LWM2M Cellular Connectivity + + 10 + urn:oma:lwm2m:oma:10 + 1.0 + 1.0 + Single + Optional + + SMSC address + RW + Single + Optional + String + + + + + Disable radio period + RW + Single + Optional + Integer + 0..65535 + + 0 the device SHALL disconnect. When the period has elapsed the device MAY reconnect.]]> + + Module activation code + RW + Single + Optional + String + + + + + Vendor specific extensions + R + Single + Optional + Objlnk + + + + + PSM Timer (1) + RW + Single + Optional + Integer + + s + + + Active Timer (1) + RW + Single + Optional + Integer + + s + + + Serving PLMN Rate control + R + Single + Optional + Integer + + + + + eDRX parameters for Iu mode (1) + RW + Single + Optional + Opaque + 8 bit + + + + eDRX parameters for WB-S1 mode (1) + RW + Single + Optional + Opaque + 8 bit + + + + eDRX parameters for NB-S1 mode (1) + RW + Single + Optional + Opaque + 8 bit + + + + eDRX parameters for A/Gb mode (1) + RW + Single + Optional + Opaque + 8 bit + + + + Activated Profile Names + R + Multiple + Mandatory + Objlnk + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/LWM2M_Connectivity_Monitoring-v1_0_2.xml b/transport/lwm2m/src/main/data/models/LWM2M_Connectivity_Monitoring-v1_0_2.xml new file mode 100644 index 0000000000..48e942983d --- /dev/null +++ b/transport/lwm2m/src/main/data/models/LWM2M_Connectivity_Monitoring-v1_0_2.xml @@ -0,0 +1,167 @@ + + + + + Connectivity Monitoring + + This LwM2M Object enables monitoring of parameters related to network connectivity. In this general connectivity Object, the Resources are limited to the most general cases common to most network bearers. It is recommended to read the description, which refers to relevant standard development organizations (e.g. 3GPP, IEEE). The goal of the Connectivity Monitoring Object is to carry information reflecting the more up to date values of the current connection for monitoring purposes. Resources such as Link Quality, Radio Signal Strength, Cell ID are retrieved during connected mode at least for cellular networks. + + 4 + urn:oma:lwm2m:oma:4 + 1.0 + 1.0 + Single + Optional + + + Network Bearer + R + Single + Mandatory + Integer + 0-50 + + + Indicates the network bearer used for the current LwM2M communication session from the network bearer list below. The number range is split into three categories: 0 - 20 are Cellular Bearers 21 - 40 are Wireless Bearers 41 - 50 are Wireline Bearers More specifically: 0: GSM cellular network 1: TD-SCDMA cellular network 2: WCDMA cellular network 3: CDMA2000 cellular network 4: WiMAX cellular network 5: LTE-TDD cellular network 6: LTE-FDD cellular network 7: NB-IoT 8 - 20: Reserved for other types of cellular network 21: WLAN network 22: Bluetooth network 23: IEEE 802.15.4 network 24 - 40: Reserved for other types of local wireless network 41: Ethernet 42: DSL 43: PLC 44 - 50: reserved for other types of wireline networks. + + + + Available Network Bearer + R + Multiple + Mandatory + Integer + 0-50 + + + Indicates a list of current available network bearer. Each Resource Instance has a value from the network bearer list. + + + + Radio Signal Strength + R + Single + Mandatory + Integer + + dBm + + Indicates the average value of the received signal strength indication used in the current network bearer (as indicated by Resource 0 of this Object). For the following network bearers the signal strength parameters indicated below are represented by this resource: GSM: RSSI UMTS: RSCP LTE: RSRP NB-IoT: NRSRP For more details on Network Measurement Report, refer to the appropriate Cellular or Wireless Network standards, (e.g. for LTE Cellular Network refer to 3GPP TS 36.133 specification). + + + + Link Quality + R + Single + Optional + Integer + + + + This contains received link quality e.g. LQI for IEEE 802.15.4 (range 0...255), RxQual Downlink for GSM (range 0...7, refer to [3GPP 44.018] for more details on Network Measurement Report encoding), RSRQ for LTE, (refer to [3GPP 36.214]), NRSRQ for NB-IoT (refer to [3GPP 36.214]). + + + + IP Addresses + R + Multiple + Mandatory + String + + + + The IP addresses assigned to the connectivity interface. (e.g. IPv4, IPv6, etc.) + + + + Router IP Addresses + R + Multiple + Optional + String + + + + The IP address of the next-hop IP router, on each of the interfaces specified in resource 4 (IP Addresses). Note: This IP Address doesn’t indicate the Server IP address. + + + + Link Utilization + R + Single + Optional + Integer + 0-100 + % + + The percentage indicating the average utilization of the link to the next-hop IP router. + + + + APN + R + Multiple + Optional + String + + + + Access Point Name in case Network Bearer Resource is a Cellular Network. + + + + Cell ID + R + Single + Optional + Integer + + + + Serving Cell ID in case Network Bearer Resource is a Cellular Network. As specified in TS [3GPP 23.003] and in [3GPP. 24.008]. Range (0...65535) in GSM/EDGE UTRAN Cell ID has a length of 28 bits. Cell Identity in WCDMA/TD-SCDMA. Range: (0...268435455). LTE Cell ID has a length of 28 bits. Parameter definitions in [3GPP 25.331]. + + + + SMNC + R + Single + Optional + Integer + 0-999 + % + + Serving Mobile Network Code. This is applicable when the Network Bearer Resource value is referring to a cellular network. As specified in TS [3GPP 23.003]. + + + + SMCC + R + Single + Optional + Integer + 0-999 + + + Serving Mobile Country Code. This is applicable when the Network Bearer Resource value is referring to a cellular network. As specified in TS [3GPP 23.003]. + + + + + + diff --git a/transport/lwm2m/src/main/data/models/LWM2M_DevCapMgmt-v1_0.xml b/transport/lwm2m/src/main/data/models/LWM2M_DevCapMgmt-v1_0.xml new file mode 100644 index 0000000000..f45689a64f --- /dev/null +++ b/transport/lwm2m/src/main/data/models/LWM2M_DevCapMgmt-v1_0.xml @@ -0,0 +1,130 @@ + + + + + DevCapMgmt + + 15 + urn:oma:lwm2m:oma:15 + Multiple + Optional + + Property + R + Single + Mandatory + String + + + + + Group + R + Single + Mandatory + Integer + 0-15 + + + + Description + R + Single + Optional + String + + + + + Attached + R + Single + Optional + Boolean + + + + + Enabled + R + Single + Mandatory + Boolean + + + + + opEnable + E + Single + Mandatory + + + + + + opDisable + E + Multiple + Mandatory + + + + + + NotifyEn + RW + Single + Optional + Boolean + + + + + + + \ No newline at end of file diff --git a/transport/lwm2m/src/main/data/models/LWM2M_LOCKWIPE-v1_0_1.xml b/transport/lwm2m/src/main/data/models/LWM2M_LOCKWIPE-v1_0_1.xml new file mode 100644 index 0000000000..913d294acf --- /dev/null +++ b/transport/lwm2m/src/main/data/models/LWM2M_LOCKWIPE-v1_0_1.xml @@ -0,0 +1,98 @@ + + + + + Lock and Wipe + + 8 + urn:oma:lwm2m:oma:8 + Single + Optional + + State + RW + Single + Mandatory + Integer + 0-2 + + + + Lock target + W + Multiple + Mandatory + String + + + + + Wipe item + R + Multiple + Optional + String + + + + + Wipe + E + Single + Mandatory + + + + + + + Wipe target + W + Multiple + Mandatory + String + + + + Lock or Wipe Operation Result + R + Single + Mandatory + Integer + 0-8 + + + + + + \ No newline at end of file diff --git a/transport/lwm2m/src/main/data/models/LWM2M_Portfolio-v1_0.xml b/transport/lwm2m/src/main/data/models/LWM2M_Portfolio-v1_0.xml new file mode 100644 index 0000000000..993a3fa126 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/LWM2M_Portfolio-v1_0.xml @@ -0,0 +1,81 @@ + + + + + Portfolio + + 16 + urn:oma:lwm2m:oma:161.0 + 1.0Multiple + Optional + + Identity + RW + Multiple + Mandatory + String + + + + + GetAuthData + E + Single + Optional + + + + + + AuthData + R + Multiple + Optional + Opaque + + + + + AuthStatus + R + Single + Optional + Integer + [0-2] + + + + + + \ No newline at end of file diff --git a/transport/lwm2m/src/main/data/models/LWM2M_Software_Component-v1_0.xml b/transport/lwm2m/src/main/data/models/LWM2M_Software_Component-v1_0.xml new file mode 100644 index 0000000000..9d2f886ed5 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/LWM2M_Software_Component-v1_0.xml @@ -0,0 +1,95 @@ + + + + + LWM2M Software Component + + 14 + urn:oma:lwm2m:oma:14 + Multiple + Optional + + + Component Identity + R + Single + Optional + String + 0-255 bytes + + + + + Component Pack + R + Single + Optional + Opaque + + + + + + Component Version + R + Single + Optional + String + 0-255 bytes + + + + + Activate + E + Single + Optional + + + + + + + Deactivate + E + Single + Optional + + + + + + Activation State + R + Single + Optional + Boolean + + + + + + + + diff --git a/transport/lwm2m/src/main/data/models/LWM2M_Software_Management-v1_0.xml b/transport/lwm2m/src/main/data/models/LWM2M_Software_Management-v1_0.xml new file mode 100644 index 0000000000..7be031c6d5 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/LWM2M_Software_Management-v1_0.xml @@ -0,0 +1,235 @@ + + + + + LWM2M Software Management + + 9 + urn:oma:lwm2m:oma:9 + Multiple + Optional + + + PkgName + R + Single + Mandatory + String + 0-255 bytes + + + + + PkgVersion + R + Single + Mandatory + String + 0-255 bytes + + + + + Package + W + Single + Optional + Opaque + + + + + + Package URI + W + Single + Optional + String + 0-255 bytes + + + + + Install + E + Single + Mandatory + + + + + + Checkpoint + R + Single + Optional + Objlnk + + + + + Uninstall + E + Single + Mandatory + + + + + + Update State + R + Single + Mandatory + Integer + 0-4 + + + + Update Supported Objects + RW + Single + Optional + Boolean + + + + + Update Result + R + Single + Mandatory + Integer + 0-200 + + + + Activate + E + Single + Mandatory + + + + + + Deactivate + E + Single + Mandatory + + + + + + Activation State + R + Single + Mandatory + Boolean + + + + + Package Settings + RW + Single + Optional + Objlnk + + + + + User Name + W + Single + Optional + String + 0-255 bytes + + + + Password + W + Single + Optional + String + 0-255 bytes + + + + + + diff --git a/transport/lwm2m/src/main/data/models/LWM2M_WLAN_connectivity4-v1_0.xml b/transport/lwm2m/src/main/data/models/LWM2M_WLAN_connectivity4-v1_0.xml new file mode 100644 index 0000000000..c18a673a10 --- /dev/null +++ b/transport/lwm2m/src/main/data/models/LWM2M_WLAN_connectivity4-v1_0.xml @@ -0,0 +1,528 @@ + + + + + WLAN connectivity + + 12 + urn:oma:lwm2m:oma:12 + + + Multiple + Optional + + Interface name + RW + Single + Mandatory + String + + + + + Enable + RW + Single + Mandatory + Boolean + + + + + Radio Enabled + RW + Single + Optional + Integer + + + + + Status + R + Single + Mandatory + Integer + + + + + BSSID + R + Single + Mandatory + String + 12 bytes + + + + SSID + RW + Single + Mandatory + String + 1-32 Bytes + + + + Broadcast SSID + RW + Single + Optional + Boolean + + + + + Beacon Enabled + RW + Single + Optional + Boolean + + + + + Mode + RW + Single + Mandatory + Integer + + + + + Channel + RW + Single + Mandatory + Integer + 0-255 + + + + Auto Channel + RW + Single + Optional + Boolean + + + + + Supported Channels + RW + Multiple + Optional + Integer + + + + + Channels In Use + RW + Multiple + Optional + Integer + + + + + Regulatory Domain + RW + Single + Optional + String + 3 Bytes + + + + Standard + RW + Single + Mandatory + Integer + + + + + Authentication Mode + RW + Single + Mandatory + Integer + + + + + Encryption Mode + RW + Single + Optional + Integer + + + + + WPA Pre Shared Key + W + Single + Optional + String + 64 Bytes + + + + WPA Key Phrase + W + Single + Optional + String + 1-64 Bytes + + + + WEP Encryption Type + RW + Single + Optional + Integer + + + + + WEP Key Index + RW + Single + Optional + Integer + [1:4] + + + + WEP Key Phrase + W + Single + Optional + String + 1-64 Bytes + + + + WEP Key 1 + W + Single + Optional + String + 0 or 26 Bytes + + + + WEP Key 2 + W + Single + Optional + String + 0 or 26 Bytes + + + + WEP Key 3 + W + Single + Optional + String + 10 or 26 Bytes + + + + WEP Key 4 + W + Single + Optional + String + 10 or 26 Bytes + + + + RADIUS Server + RW + Single + Optional + String + 1-256 Bytes + + + + RADIUS Server Port + RW + Single + Optional + Integer + + + + + RADIUS Secret + W + Single + Optional + String + 1-256 Bytes + + + + WMM Supported + R + Single + Optional + Boolean + + + + + WMM Enabled + RW + Single + Optional + Boolean + + + + + MAC Control Enabled + RW + Single + Optional + Boolean + + + + + MAC Address List + RW + Multiple + Optional + String + 12 Bytes + + + + Total Bytes Sent + R + Single + Optional + Integer + + + + + Total Bytes Received + R + Single + Optional + Integer + + + + + Total Packets Sent + R + Single + Optional + Integer + + + + + Total Packets Received + R + Single + Optional + Integer + + + + + Transmit Errors + R + Single + Optional + Integer + + + + + Receive Errors + R + Single + Optional + Integer + + + + + Unicast Packets Sent + R + Single + Optional + Integer + + + + + Unicast Packets Received + R + Single + Optional + Integer + + + + + Multicast Packets Received + R + Single + Optional + Integer + + + + + Multicast Packets Received + R + Single + Optional + Integer + + + + + Broadcast Packets Sent + R + Single + Optional + Integer + + + + + 44 Broadcast Packets Received + R + Single + Optional + Integer + + + + + Discard Packets Sent + R + Single + Optional + Integer + + + + + Discard Packets Received + R + Single + Optional + Integer + + + + + Unknown Packets Received + R + Single + Optional + Integer + + + + + Vendor specific extensions + R + Single + Optional + Objlnk + + + + + + + \ No newline at end of file diff --git a/transport/lwm2m/src/main/data/models/LwM2M_BinaryAppDataContainer-v1_0_1.xml b/transport/lwm2m/src/main/data/models/LwM2M_BinaryAppDataContainer-v1_0_1.xml new file mode 100644 index 0000000000..374dac72bc --- /dev/null +++ b/transport/lwm2m/src/main/data/models/LwM2M_BinaryAppDataContainer-v1_0_1.xml @@ -0,0 +1,164 @@ + + + + + + BinaryAppDataContainer + + 19 + urn:oma:lwm2m:oma:19 + 1.0 + 1.0 + Multiple + Optional + + Data + RW + + + + Multiple + Mandatory + Opaque + + + + + Data Priority + RW + Single + Optional + Integer + 1 bytes + + + + Data Creation Time + RW + Single + Optional + Time + + + + + Data Description + RW + Single + Optional + String + 32 bytes + + + + Data Format + RW + Single + Optional + String + 32 bytes + + + + App ID + RW + Single + Optional + Integer + 2 bytes + + + + + + diff --git a/transport/lwm2m/src/main/data/models/LwM2M_EventLog-V1_0.xml b/transport/lwm2m/src/main/data/models/LwM2M_EventLog-V1_0.xml new file mode 100644 index 0000000000..d7054de9ff --- /dev/null +++ b/transport/lwm2m/src/main/data/models/LwM2M_EventLog-V1_0.xml @@ -0,0 +1,101 @@ + + + + + + Event Log + + 20 + urn:oma:lwm2m:oma:20 + 1.0 + 1.0 + Single + Optional + + LogClass + RW + Single + Optional + Integer + 255 + + + + LogStart + E + Single + Optional + + + + + + LogStop + E + Single + Optional + + + + + + LogStatus + R + Single + Optional + Integer + 8-Bits + + + + LogData + R + Single + Mandatory + Opaque + + + + + LogDataFormat + RW + Single + Optional + Integer + 255 + + + + + + \ No newline at end of file diff --git a/transport/lwm2m/src/main/java/org/thingsboard/server/lwm2m/ThingsboardLwm2mTransportApplication.java b/transport/lwm2m/src/main/java/org/thingsboard/server/lwm2m/ThingsboardLwm2mTransportApplication.java new file mode 100644 index 0000000000..1b3423055e --- /dev/null +++ b/transport/lwm2m/src/main/java/org/thingsboard/server/lwm2m/ThingsboardLwm2mTransportApplication.java @@ -0,0 +1,48 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.lwm2m; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.annotation.EnableScheduling; + +import java.util.Arrays; + +@SpringBootConfiguration +@EnableAsync +@EnableScheduling +@ComponentScan({"org.thingsboard.server.lwm2m", "org.thingsboard.server.common", "org.thingsboard.server.transport.lwm2m", "org.thingsboard.server.queue"}) +public class ThingsboardLwm2mTransportApplication { + + private static final String SPRING_CONFIG_NAME_KEY = "--spring.config.name"; + private static final String DEFAULT_SPRING_CONFIG_PARAM = SPRING_CONFIG_NAME_KEY + "=" + "tb-lwm2m-transport"; + + public static void main(String[] args) { + SpringApplication.run(ThingsboardLwm2mTransportApplication.class, updateArguments(args)); + } + + private static String[] updateArguments(String[] args) { + if (Arrays.stream(args).noneMatch(arg -> arg.startsWith(SPRING_CONFIG_NAME_KEY))) { + String[] modifiedArgs = new String[args.length + 1]; + System.arraycopy(args, 0, modifiedArgs, 0, args.length); + modifiedArgs[args.length] = DEFAULT_SPRING_CONFIG_PARAM; + return modifiedArgs; + } + return args; + } +} diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m-device-profile-transport-configuration.component.html b/transport/lwm2m/src/main/resources/logback.xml similarity index 52% rename from ui-ngx/src/app/modules/home/components/profile/device/lwm2m-device-profile-transport-configuration.component.html rename to transport/lwm2m/src/main/resources/logback.xml index 03530c2b2e..e96ad177ef 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m-device-profile-transport-configuration.component.html +++ b/transport/lwm2m/src/main/resources/logback.xml @@ -1,3 +1,4 @@ + -

- - -
+ + + + + + %d{ISO8601} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + + \ No newline at end of file diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml new file mode 100644 index 0000000000..d6fe7b5b1f --- /dev/null +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -0,0 +1,301 @@ +# +# Copyright © 2016-2020 The Thingsboard Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# If you enabled process metrics you should also enable 'web-environment'. +spring.main.web-environment: "${WEB_APPLICATION_ENABLE:false}" +# If you enabled process metrics you should set 'web-application-type' to 'servlet' value. +spring.main.web-application-type: "${WEB_APPLICATION_TYPE:none}" + +server: + # Server bind address (has no effect if web-environment is disabled). + address: "${HTTP_BIND_ADDRESS:0.0.0.0}" + # Server bind port (has no effect if web-environment is disabled). + port: "${HTTP_BIND_PORT:8083}" + +# Zookeeper connection parameters. Used for service discovery. +zk: + # Enable/disable zookeeper discovery service. + enabled: "${ZOOKEEPER_ENABLED:false}" + # Zookeeper connect string + url: "${ZOOKEEPER_URL:localhost:2181}" + # Zookeeper retry interval in milliseconds + retry_interval_ms: "${ZOOKEEPER_RETRY_INTERVAL_MS:3000}" + # Zookeeper connection timeout in milliseconds + connection_timeout_ms: "${ZOOKEEPER_CONNECTION_TIMEOUT_MS:3000}" + # Zookeeper session timeout in milliseconds + session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" + # Name of the directory in zookeeper 'filesystem' + zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" + +# LWM2M server parameters +transport: + lwm2m: + # Enable/disable lvm2m transport protocol. + enabled: "${LWM2M_ENABLED:true}" + # We choose a default timeout a bit higher to the MAX_TRANSMIT_WAIT(62-93s) which is the time from starting to + # send a Confirmable message to the time when an acknowledgement is no longer expected. + # DEFAULT_TIMEOUT = 2 * 60 * 1000l; 2 min in ms + timeout: "${LWM2M_TIMEOUT:120000}" + # model_path_file: "${LWM2M_MODEL_PATH_FILE:./common/transport/lwm2m/src/main/resources/models/}" + model_path_file: "${LWM2M_MODEL_PATH_FILE:}" + support_deprecated_ciphers_enable: "${LWM2M_SUPPORT_DEPRECATED_CIPHERS_ENABLED:true}" + secure: + # Only Certificate_x509: + # To get helps about files format and how to generate it, see: https://github.com/eclipse/leshan/wiki/Credential-files-format + # Create new X509 Certificates: common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh + key_store_type: "${LWM2M_KEYSTORE_TYPE:JKS}" + # key_store_type: "${LWM2M_KEYSTORE_TYPE:PKCS12}" + # key_store_path_file: "${KEY_STORE_PATH_FILE:/usr/share/thingsboard/conf/credentials/serverKeyStore.jks}" + key_store_path_file: "${KEY_STORE_PATH_FILE:}" + key_store_password: "${LWM2M_KEYSTORE_PASSWORD_SERVER:server_ks_password}" + root_alias: "${LWM2M_SERVER_ROOT_CA:rootca}" + enable_gen_psk_rpk: "${ENABLE_GEN_PSK_RPK:true}" + server: + bind_address: "${LWM2M_BIND_ADDRESS:0.0.0.0}" + bind_port: "${LWM2M_BIND_PORT:5685}" + bind_port_cert: "${LWM2M_BIND_PORT_CERT:5687}" + secure: + start_all: "${START_SERVER_ALL:true}" + #leshan.core (V1_1) + #DTLS security modes: + #0: Pre-Shared Key mode + #1: Raw Public Key mode + #2: Certificate mode X509 + #3: NoSec mode * + #OMA-TS-LightweightM2M_Core-V1_1_1-20190617-A (add) + #4: Certificate mode X509 with EST + # If only startAll == false + dtls_mode: "${LWM2M_SECURITY_MODE:1}" + bind_address: "${LWM2M_BIND_ADDRESS:0.0.0.0}" + bind_port: "${LWM2M_BIND_PORT_SEC:5686}" + bind_port_cert: "${LWM2M_BIND_PORT_SEC_CERT:5688}" + # Only RPK: Public & Private Key + # create_rpk: "${CREATE_RPK:}" + public_x: "${LWM2M_SERVER_PUBLIC_X:405354ea8893471d9296afbc8b020a5c6201b0bb25812a53b849d4480fa5f069}" + public_y: "${LWM2M_SERVER_PUBLIC_Y:30c9237e946a3a1692c1cafaa01a238a077f632c99371348337512363f28212b}" + private_s: "${LWM2M_SERVER_PRIVATE_S:274671fe40ce937b8a6352cf0a418e8a39e4bf0bb9bf74c910db953c20c73802}" + # Only Certificate_x509: + alias: "${LWM2M_KEYSTORE_ALIAS_SERVER:server}" + bootstrap: + enable: "${BOOTSTRAP:true}" + bind_address: "${LWM2M_BIND_ADDRESS_BS:0.0.0.0}" + bind_port: "${LWM2M_BIND_PORT_BS:5689}" + bind_port_cert: "${LWM2M_BIND_PORT_SER_BS:5691}" + secure: + start_all: "${START_BOOTSTRAP_ALL:true}" + # If only startAll == false + dtls_mode: "${LWM2M_SECURITY_MODE_BS:1}" + bind_address: "${LWM2M_BIND_ADDRESS_BS:0.0.0.0}" + bind_port: "${LWM2M_BIND_PORT_SEC_BS:5690}" + bind_port_cert: "${LWM2M_BIND_PORT_SEC_CERT_BS:5692}" + # Only RPK: Public & Private Key + public_x: "${LWM2M_SERVER_PUBLIC_X_BS:993ef2b698c6a9c0c1d8be78b13a9383c0854c7c7c7a504d289b403794648183}" + public_y: "${LWM2M_SERVER_PUBLIC_Y_BS:267412d5fc4e5ceb2257cb7fd7f76ebdac2fa9aa100afb162e990074cc0bfaa2}" + private_s: "${LWM2M_SERVER_PRIVATE_S_BS:9dbdbb073fc63570693a9aaf1013414e261c571f27e27fc6a8c1c2ad9347875a}" + # Only Certificate_x509: + alias: "${LWM2M_KEYSTORE_ALIAS_BOOTSTRAP:bootstrap}" + # Redis + redis_url: "${LWM2M_REDIS_URL:''}" + sessions: + inactivity_timeout: "${TB_TRANSPORT_SESSIONS_INACTIVITY_TIMEOUT:300000}" + report_timeout: "${TB_TRANSPORT_SESSIONS_REPORT_TIMEOUT:30000}" + json: + # Cast String data types to Numeric if possible when processing Telemetry/Attributes JSON + type_cast_enabled: "${JSON_TYPE_CAST_ENABLED:true}" + # Maximum allowed string value length when processing Telemetry/Attributes JSON (0 value disables string value length check) + max_string_value_length: "${JSON_MAX_STRING_VALUE_LENGTH:0}" + +queue: + type: "${TB_QUEUE_TYPE:kafka}" # kafka (Apache Kafka) or aws-sqs (AWS SQS) or pubsub (PubSub) or service-bus (Azure Service Bus) or rabbitmq (RabbitMQ) + kafka: + bootstrap.servers: "${TB_KAFKA_SERVERS:localhost:9092}" + acks: "${TB_KAFKA_ACKS:all}" + retries: "${TB_KAFKA_RETRIES:1}" + batch.size: "${TB_KAFKA_BATCH_SIZE:16384}" + linger.ms: "${TB_KAFKA_LINGER_MS:1}" + buffer.memory: "${TB_BUFFER_MEMORY:33554432}" + replication_factor: "${TB_QUEUE_KAFKA_REPLICATION_FACTOR:1}" + use_confluent_cloud: "${TB_QUEUE_KAFKA_USE_CONFLUENT_CLOUD:false}" + confluent: + ssl.algorithm: "${TB_QUEUE_KAFKA_CONFLUENT_SSL_ALGORITHM:https}" + sasl.mechanism: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_MECHANISM:PLAIN}" + sasl.config: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_JAAS_CONFIG:org.apache.kafka.common.security.plain.PlainLoginModule required username=\"CLUSTER_API_KEY\" password=\"CLUSTER_API_SECRET\";}" + security.protocol: "${TB_QUEUE_KAFKA_CONFLUENT_SECURITY_PROTOCOL:SASL_SSL}" + other: + topic-properties: + rule-engine: "${TB_QUEUE_KAFKA_RE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}" + core: "${TB_QUEUE_KAFKA_CORE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}" + transport-api: "${TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}" + notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}" + js-executor: "${TB_QUEUE_KAFKA_JE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:104857600;partitions:100}" + aws_sqs: + use_default_credential_provider_chain: "${TB_QUEUE_AWS_SQS_USE_DEFAULT_CREDENTIAL_PROVIDER_CHAIN:false}" + access_key_id: "${TB_QUEUE_AWS_SQS_ACCESS_KEY_ID:YOUR_KEY}" + secret_access_key: "${TB_QUEUE_AWS_SQS_SECRET_ACCESS_KEY:YOUR_SECRET}" + region: "${TB_QUEUE_AWS_SQS_REGION:YOUR_REGION}" + threads_per_topic: "${TB_QUEUE_AWS_SQS_THREADS_PER_TOPIC:1}" + queue-properties: + rule-engine: "${TB_QUEUE_AWS_SQS_RE_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" + core: "${TB_QUEUE_AWS_SQS_CORE_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" + transport-api: "${TB_QUEUE_AWS_SQS_TA_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" + notifications: "${TB_QUEUE_AWS_SQS_NOTIFICATIONS_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" + js-executor: "${TB_QUEUE_AWS_SQS_JE_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" + # VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds + pubsub: + project_id: "${TB_QUEUE_PUBSUB_PROJECT_ID:YOUR_PROJECT_ID}" + service_account: "${TB_QUEUE_PUBSUB_SERVICE_ACCOUNT:YOUR_SERVICE_ACCOUNT}" + max_msg_size: "${TB_QUEUE_PUBSUB_MAX_MSG_SIZE:1048576}" #in bytes + max_messages: "${TB_QUEUE_PUBSUB_MAX_MESSAGES:1000}" + queue-properties: + rule-engine: "${TB_QUEUE_PUBSUB_RE_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" + core: "${TB_QUEUE_PUBSUB_CORE_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" + transport-api: "${TB_QUEUE_PUBSUB_TA_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" + notifications: "${TB_QUEUE_PUBSUB_NOTIFICATIONS_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" + js-executor: "${TB_QUEUE_PUBSUB_JE_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" + service_bus: + namespace_name: "${TB_QUEUE_SERVICE_BUS_NAMESPACE_NAME:YOUR_NAMESPACE_NAME}" + sas_key_name: "${TB_QUEUE_SERVICE_BUS_SAS_KEY_NAME:YOUR_SAS_KEY_NAME}" + sas_key: "${TB_QUEUE_SERVICE_BUS_SAS_KEY:YOUR_SAS_KEY}" + max_messages: "${TB_QUEUE_SERVICE_BUS_MAX_MESSAGES:1000}" + queue-properties: + rule-engine: "${TB_QUEUE_SERVICE_BUS_RE_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" + core: "${TB_QUEUE_SERVICE_BUS_CORE_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" + transport-api: "${TB_QUEUE_SERVICE_BUS_TA_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" + notifications: "${TB_QUEUE_SERVICE_BUS_NOTIFICATIONS_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" + js-executor: "${TB_QUEUE_SERVICE_BUS_JE_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" + rabbitmq: + exchange_name: "${TB_QUEUE_RABBIT_MQ_EXCHANGE_NAME:}" + host: "${TB_QUEUE_RABBIT_MQ_HOST:localhost}" + port: "${TB_QUEUE_RABBIT_MQ_PORT:5672}" + virtual_host: "${TB_QUEUE_RABBIT_MQ_VIRTUAL_HOST:/}" + username: "${TB_QUEUE_RABBIT_MQ_USERNAME:YOUR_USERNAME}" + password: "${TB_QUEUE_RABBIT_MQ_PASSWORD:YOUR_PASSWORD}" + automatic_recovery_enabled: "${TB_QUEUE_RABBIT_MQ_AUTOMATIC_RECOVERY_ENABLED:false}" + connection_timeout: "${TB_QUEUE_RABBIT_MQ_CONNECTION_TIMEOUT:60000}" + handshake_timeout: "${TB_QUEUE_RABBIT_MQ_HANDSHAKE_TIMEOUT:10000}" + queue-properties: + rule-engine: "${TB_QUEUE_RABBIT_MQ_RE_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" + core: "${TB_QUEUE_RABBIT_MQ_CORE_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" + transport-api: "${TB_QUEUE_RABBIT_MQ_TA_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" + notifications: "${TB_QUEUE_RABBIT_MQ_NOTIFICATIONS_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" + js-executor: "${TB_QUEUE_RABBIT_MQ_JE_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" + partitions: + hash_function_name: "${TB_QUEUE_PARTITIONS_HASH_FUNCTION_NAME:murmur3_128}" + virtual_nodes_size: "${TB_QUEUE_PARTITIONS_VIRTUAL_NODES_SIZE:16}" + transport_api: + requests_topic: "${TB_QUEUE_TRANSPORT_API_REQUEST_TOPIC:tb_transport.api.requests}" + responses_topic: "${TB_QUEUE_TRANSPORT_API_RESPONSE_TOPIC:tb_transport.api.responses}" + max_pending_requests: "${TB_QUEUE_TRANSPORT_MAX_PENDING_REQUESTS:10000}" + max_requests_timeout: "${TB_QUEUE_TRANSPORT_MAX_REQUEST_TIMEOUT:10000}" + max_callback_threads: "${TB_QUEUE_TRANSPORT_MAX_CALLBACK_THREADS:100}" + request_poll_interval: "${TB_QUEUE_TRANSPORT_REQUEST_POLL_INTERVAL_MS:25}" + response_poll_interval: "${TB_QUEUE_TRANSPORT_RESPONSE_POLL_INTERVAL_MS:25}" + core: + topic: "${TB_QUEUE_CORE_TOPIC:tb_core}" + poll-interval: "${TB_QUEUE_CORE_POLL_INTERVAL_MS:25}" + partitions: "${TB_QUEUE_CORE_PARTITIONS:10}" + pack-processing-timeout: "${TB_QUEUE_CORE_PACK_PROCESSING_TIMEOUT_MS:60000}" + stats: + enabled: "${TB_QUEUE_CORE_STATS_ENABLED:false}" + print-interval-ms: "${TB_QUEUE_CORE_STATS_PRINT_INTERVAL_MS:10000}" + js: + # JS Eval request topic + request_topic: "${REMOTE_JS_EVAL_REQUEST_TOPIC:js_eval.requests}" + # JS Eval responses topic prefix that is combined with node id + response_topic_prefix: "${REMOTE_JS_EVAL_RESPONSE_TOPIC:js_eval.responses}" + # JS Eval max pending requests + max_pending_requests: "${REMOTE_JS_MAX_PENDING_REQUESTS:10000}" + # JS Eval max request timeout + max_requests_timeout: "${REMOTE_JS_MAX_REQUEST_TIMEOUT:10000}" + # JS response poll interval + response_poll_interval: "${REMOTE_JS_RESPONSE_POLL_INTERVAL_MS:25}" + # JS response auto commit interval + response_auto_commit_interval: "${REMOTE_JS_RESPONSE_AUTO_COMMIT_INTERVAL_MS:100}" + rule-engine: + topic: "${TB_QUEUE_RULE_ENGINE_TOPIC:tb_rule_engine}" + poll-interval: "${TB_QUEUE_RULE_ENGINE_POLL_INTERVAL_MS:25}" + pack-processing-timeout: "${TB_QUEUE_RULE_ENGINE_PACK_PROCESSING_TIMEOUT_MS:60000}" + stats: + enabled: "${TB_QUEUE_RULE_ENGINE_STATS_ENABLED:true}" + print-interval-ms: "${TB_QUEUE_RULE_ENGINE_STATS_PRINT_INTERVAL_MS:60000}" + queues: + - name: "${TB_QUEUE_RE_MAIN_QUEUE_NAME:Main}" + topic: "${TB_QUEUE_RE_MAIN_TOPIC:tb_rule_engine.main}" + poll-interval: "${TB_QUEUE_RE_MAIN_POLL_INTERVAL_MS:25}" + partitions: "${TB_QUEUE_RE_MAIN_PARTITIONS:10}" + pack-processing-timeout: "${TB_QUEUE_RE_MAIN_PACK_PROCESSING_TIMEOUT_MS:60000}" + submit-strategy: + type: "${TB_QUEUE_RE_MAIN_SUBMIT_STRATEGY_TYPE:BURST}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL + # For BATCH only + batch-size: "${TB_QUEUE_RE_MAIN_SUBMIT_STRATEGY_BATCH_SIZE:1000}" # Maximum number of messages in batch + processing-strategy: + type: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_TYPE:SKIP_ALL_FAILURES}" # SKIP_ALL_FAILURES, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT + # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT + retries: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_RETRIES:3}" # Number of retries, 0 is unlimited + failure-percentage: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages; + pause-between-retries: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_RETRY_PAUSE:3}"# Time in seconds to wait in consumer thread before retries; + - name: "${TB_QUEUE_RE_HP_QUEUE_NAME:HighPriority}" + topic: "${TB_QUEUE_RE_HP_TOPIC:tb_rule_engine.hp}" + poll-interval: "${TB_QUEUE_RE_HP_POLL_INTERVAL_MS:25}" + partitions: "${TB_QUEUE_RE_HP_PARTITIONS:10}" + pack-processing-timeout: "${TB_QUEUE_RE_HP_PACK_PROCESSING_TIMEOUT_MS:60000}" + submit-strategy: + type: "${TB_QUEUE_RE_HP_SUBMIT_STRATEGY_TYPE:BURST}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL + # For BATCH only + batch-size: "${TB_QUEUE_RE_HP_SUBMIT_STRATEGY_BATCH_SIZE:100}" # Maximum number of messages in batch + processing-strategy: + type: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_TYPE:RETRY_FAILED_AND_TIMED_OUT}" # SKIP_ALL_FAILURES, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT + # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT + retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_RETRIES:0}" # Number of retries, 0 is unlimited + failure-percentage: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages; + pause-between-retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_RETRY_PAUSE:5}"# Time in seconds to wait in consumer thread before retries; + - name: "${TB_QUEUE_RE_SQ_QUEUE_NAME:SequentialByOriginator}" + topic: "${TB_QUEUE_RE_SQ_TOPIC:tb_rule_engine.sq}" + poll-interval: "${TB_QUEUE_RE_SQ_POLL_INTERVAL_MS:25}" + partitions: "${TB_QUEUE_RE_SQ_PARTITIONS:10}" + pack-processing-timeout: "${TB_QUEUE_RE_SQ_PACK_PROCESSING_TIMEOUT_MS:60000}" + submit-strategy: + type: "${TB_QUEUE_RE_SQ_SUBMIT_STRATEGY_TYPE:SEQUENTIAL_BY_ORIGINATOR}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL + # For BATCH only + batch-size: "${TB_QUEUE_RE_SQ_SUBMIT_STRATEGY_BATCH_SIZE:100}" # Maximum number of messages in batch + processing-strategy: + type: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_TYPE:RETRY_FAILED_AND_TIMED_OUT}" # SKIP_ALL_FAILURES, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT + # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT + retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_RETRIES:3}" # Number of retries, 0 is unlimited + failure-percentage: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages; + pause-between-retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_RETRY_PAUSE:5}"# Time in seconds to wait in consumer thread before retries; + transport: + # For high priority notifications that require minimum latency and processing time + notifications_topic: "${TB_QUEUE_TRANSPORT_NOTIFICATIONS_TOPIC:tb_transport.notifications}" + poll_interval: "${TB_QUEUE_TRANSPORT_NOTIFICATIONS_POLL_INTERVAL_MS:25}" + +service: + type: "${TB_SERVICE_TYPE:tb-transport}" + # Unique id for this service (autogenerated if empty) + id: "${TB_SERVICE_ID:}" + tenant_id: "${TB_SERVICE_TENANT_ID:}" # empty or specific tenant id. + + +metrics: + # Enable/disable actuator metrics. + enabled: "${METRICS_ENABLED:false}" + +management: + endpoints: + web: + exposure: + # Expose metrics endpoint (use value 'prometheus' to enable prometheus metrics). + include: '${METRICS_ENDPOINTS_EXPOSE:info}' diff --git a/transport/pom.xml b/transport/pom.xml index 424c94842f..8d4c1d6660 100644 --- a/transport/pom.xml +++ b/transport/pom.xml @@ -37,6 +37,7 @@ http mqtt coap + lwm2m diff --git a/ui-ngx/src/app/core/http/device-profile.service.ts b/ui-ngx/src/app/core/http/device-profile.service.ts index c535878fd2..16f6edb512 100644 --- a/ui-ngx/src/app/core/http/device-profile.service.ts +++ b/ui-ngx/src/app/core/http/device-profile.service.ts @@ -22,6 +22,9 @@ import { Observable } from 'rxjs'; import { PageData } from '@shared/models/page/page-data'; import { DeviceProfile, DeviceProfileInfo, DeviceTransportType } from '@shared/models/device.models'; import { isDefinedAndNotNull } from '@core/utils'; +import { + ObjectLwM2M, ServerSecurityConfig +} from "../../modules/home/components/profile/device/lwm2m/profile-config.models"; @Injectable({ providedIn: 'root' @@ -40,6 +43,18 @@ export class DeviceProfileService { return this.http.get(`/api/deviceProfile/${deviceProfileId}`, defaultHttpOptionsFromConfig(config)); } + public getLwm2mObjects(objectIds: number [], config?: RequestConfig): Observable { + return this.http.get(`/api/lwm2m/deviceProfile/${objectIds}`, defaultHttpOptionsFromConfig(config)); + } + + public getLwm2mBootstrapSecurityInfo(securityMode: string, bootstrapServerIs: boolean, config?: RequestConfig): Observable { + return this.http.get(`/api/lwm2m/deviceProfile/bootstrap/${securityMode}/${bootstrapServerIs}`, defaultHttpOptionsFromConfig(config)); + } + + public getLwm2mObjectsPage(pageLink: PageLink, config?: RequestConfig): Observable> { + return this.http.get>(`/api/lwm2m/deviceProfile/objects${pageLink.toQuery()}`, defaultHttpOptionsFromConfig(config)); + } + public saveDeviceProfile(deviceProfile: DeviceProfile, config?: RequestConfig): Observable { return this.http.post('/api/deviceProfile', deviceProfile, defaultHttpOptionsFromConfig(config)); } diff --git a/ui-ngx/src/app/modules/home/components/device/device-credentials.component.html b/ui-ngx/src/app/modules/home/components/device/device-credentials.component.html index a8b48e30d1..44337d30a5 100644 --- a/ui-ngx/src/app/modules/home/components/device/device-credentials.component.html +++ b/ui-ngx/src/app/modules/home/components/device/device-credentials.component.html @@ -74,4 +74,29 @@ [error]="deviceCredentialsFormGroup.get('credentialsBasic').hasError('atLeastOne') ? ('device.client-id-or-user-name-necessary' | translate) : ''"> +
+ + device.lwm2m-key + + + {{ 'device.lwm2m-key-required' | translate }} + + + + device.lwm2m-value + + + {{ 'device.lwm2m-value-required' | translate }} + +
+ +
+
+
diff --git a/ui-ngx/src/app/modules/home/components/device/device-credentials.component.ts b/ui-ngx/src/app/modules/home/components/device/device-credentials.component.ts index fd6680fe17..4c622747ef 100644 --- a/ui-ngx/src/app/modules/home/components/device/device-credentials.component.ts +++ b/ui-ngx/src/app/modules/home/components/device/device-credentials.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core'; +import { Component, forwardRef, Inject, Input, OnDestroy, OnInit } from '@angular/core'; import { ControlValueAccessor, FormBuilder, @@ -34,8 +34,19 @@ import { DeviceCredentialsType } from '@shared/models/device.models'; import { Subscription } from 'rxjs'; -import { isDefinedAndNotNull } from '@core/utils'; import { distinctUntilChanged } from 'rxjs/operators'; +import { SecurityConfigComponent } from '@home/pages/device/lwm2m/security-config.component'; +import { + DEFAULT_END_POINT, + DeviceCredentialsDialogLwm2mData, + END_POINT, + getDefaultSecurityConfig, + JSON_ALL_CONFIG, + SecurityConfigModels +} from '@home/pages/device/lwm2m/security-config.models'; +import { TranslateService } from '@ngx-translate/core'; +import { MatDialog } from '@angular/material/dialog'; +import { isDefinedAndNotNull } from '@core/utils'; @Component({ selector: 'tb-device-credentials', @@ -76,7 +87,9 @@ export class DeviceCredentialsComponent implements ControlValueAccessor, OnInit, private propagateChange = (v: any) => {}; - constructor(public fb: FormBuilder) { + constructor(public fb: FormBuilder, + private translate: TranslateService, + private dialog: MatDialog) { this.deviceCredentialsFormGroup = this.fb.group({ credentialsType: [DeviceCredentialsType.ACCESS_TOKEN], credentialsId: [null], @@ -197,6 +210,14 @@ export class DeviceCredentialsComponent implements ControlValueAccessor, OnInit, this.deviceCredentialsFormGroup.get('credentialsId').updateValueAndValidity({emitEvent: false}); this.deviceCredentialsFormGroup.get('credentialsValue').setValidators([]); this.deviceCredentialsFormGroup.get('credentialsValue').updateValueAndValidity({emitEvent: false}); + break; + case DeviceCredentialsType.LWM2M_CREDENTIALS: + this.deviceCredentialsFormGroup.get('credentialsValue').setValidators([Validators.required]); + this.deviceCredentialsFormGroup.get('credentialsValue').updateValueAndValidity({emitEvent: false}); + this.deviceCredentialsFormGroup.get('credentialsId').setValidators([]); + this.deviceCredentialsFormGroup.get('credentialsId').updateValueAndValidity({emitEvent: false}); + this.deviceCredentialsFormGroup.get('credentialsBasic').disable({emitEvent: false}); + break; } } @@ -223,4 +244,28 @@ export class DeviceCredentialsComponent implements ControlValueAccessor, OnInit, onlySelf: true }); } + + openSecurityInfoLwM2mDialog($event: Event, value: string, id: string): void { + if ($event) { + $event.stopPropagation(); + $event.preventDefault(); + } + this.dialog.open(SecurityConfigComponent, { + disableClose: true, + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], + data: { + jsonAllConfig: (value === null || value.length === 0) ? getDefaultSecurityConfig() as SecurityConfigModels : JSON.parse(value) as SecurityConfigModels, + endPoint: (id === null) ? DEFAULT_END_POINT : id, + isNew: (id === null || value === null || value.length === 0) + } + }).afterClosed().subscribe( + (res) => { + if (res) { + this.deviceCredentialsFormGroup.get('credentialsValue').patchValue((Object.keys(res[JSON_ALL_CONFIG]).length === 0 || JSON.stringify(res[JSON_ALL_CONFIG]) === "[{}]") ? null : JSON.stringify(res[JSON_ALL_CONFIG])); + this.deviceCredentialsFormGroup.get('credentialsId').patchValue((Object.keys(res[END_POINT]).length === 0 || JSON.stringify(res[END_POINT]) === "[{}]") ? null : JSON.stringify(res[END_POINT]).split('\"').join('')); + this.deviceCredentialsFormGroup.get('credentialsValue').markAsDirty(); + } + } + ); + } } diff --git a/ui-ngx/src/app/modules/home/components/home-components.module.ts b/ui-ngx/src/app/modules/home/components/home-components.module.ts index 113f4ae4bb..67f86cb812 100644 --- a/ui-ngx/src/app/modules/home/components/home-components.module.ts +++ b/ui-ngx/src/app/modules/home/components/home-components.module.ts @@ -96,7 +96,6 @@ import { DeviceProfileTransportConfigurationComponent } from '@home/components/p import { DeviceProfileDialogComponent } from '@home/components/profile/device-profile-dialog.component'; import { DeviceProfileAutocompleteComponent } from '@home/components/profile/device-profile-autocomplete.component'; import { MqttDeviceProfileTransportConfigurationComponent } from '@home/components/profile/device/mqtt-device-profile-transport-configuration.component'; -import { Lwm2mDeviceProfileTransportConfigurationComponent } from '@home/components/profile/device/lwm2m-device-profile-transport-configuration.component'; import { DeviceProfileAlarmsComponent } from '@home/components/profile/alarm/device-profile-alarms.component'; import { DeviceProfileAlarmComponent } from '@home/components/profile/alarm/device-profile-alarm.component'; import { CreateAlarmRulesComponent } from '@home/components/profile/alarm/create-alarm-rules.component'; @@ -119,6 +118,7 @@ import { SmsProviderConfigurationComponent } from '@home/components/sms/sms-prov import { AwsSnsProviderConfigurationComponent } from '@home/components/sms/aws-sns-provider-configuration.component'; import { TwilioSmsProviderConfigurationComponent } from '@home/components/sms/twilio-sms-provider-configuration.component'; import { CopyDeviceCredentialsComponent } from '@home/components/device/copy-device-credentials.component'; +import { Lwm2mProfileComponentsModule } from '@home/components/profile/device/lwm2m/lwm2m-profile-components.module'; @NgModule({ declarations: @@ -198,7 +198,6 @@ import { CopyDeviceCredentialsComponent } from '@home/components/device/copy-dev DeviceProfileConfigurationComponent, DefaultDeviceProfileTransportConfigurationComponent, MqttDeviceProfileTransportConfigurationComponent, - Lwm2mDeviceProfileTransportConfigurationComponent, DeviceProfileTransportConfigurationComponent, CreateAlarmRulesComponent, AlarmRuleComponent, @@ -225,7 +224,8 @@ import { CopyDeviceCredentialsComponent } from '@home/components/device/copy-dev imports: [ CommonModule, SharedModule, - SharedHomeComponentsModule + SharedHomeComponentsModule, + Lwm2mProfileComponentsModule ], exports: [ EntitiesTableComponent, @@ -287,7 +287,6 @@ import { CopyDeviceCredentialsComponent } from '@home/components/device/copy-dev DeviceProfileConfigurationComponent, DefaultDeviceProfileTransportConfigurationComponent, MqttDeviceProfileTransportConfigurationComponent, - Lwm2mDeviceProfileTransportConfigurationComponent, DeviceProfileTransportConfigurationComponent, CreateAlarmRulesComponent, AlarmRuleComponent, @@ -307,6 +306,8 @@ import { CopyDeviceCredentialsComponent } from '@home/components/device/copy-dev AlarmScheduleDialogComponent, EditAlarmDetailsDialogComponent, DeviceProfileProvisionConfigurationComponent, + AlarmScheduleComponent, + Lwm2mProfileComponentsModule, SmsProviderConfigurationComponent, AwsSnsProviderConfigurationComponent, TwilioSmsProviderConfigurationComponent diff --git a/ui-ngx/src/app/modules/home/components/profile/device-profile-dialog.component.ts b/ui-ngx/src/app/modules/home/components/profile/device-profile-dialog.component.ts index b3e96c228d..6dea0eaad8 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device-profile-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device-profile-dialog.component.ts @@ -97,5 +97,4 @@ export class DeviceProfileDialogComponent extends ); } } - } diff --git a/ui-ngx/src/app/modules/home/components/profile/device/device-profile-transport-configuration.component.html b/ui-ngx/src/app/modules/home/components/profile/device/device-profile-transport-configuration.component.html index ea6427addd..c88f1f8b85 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/device-profile-transport-configuration.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/device-profile-transport-configuration.component.html @@ -29,11 +29,11 @@ formControlName="configuration"> - + + diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m-device-profile-transport-configuration.component.ts deleted file mode 100644 index 7a7a1d285f..0000000000 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m-device-profile-transport-configuration.component.ts +++ /dev/null @@ -1,96 +0,0 @@ -/// -/// Copyright © 2016-2020 The Thingsboard Authors -/// -/// Licensed under the Apache License, Version 2.0 (the "License"); -/// you may not use this file except in compliance with the License. -/// You may obtain a copy of the License at -/// -/// http://www.apache.org/licenses/LICENSE-2.0 -/// -/// Unless required by applicable law or agreed to in writing, software -/// distributed under the License is distributed on an "AS IS" BASIS, -/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -/// See the License for the specific language governing permissions and -/// limitations under the License. -/// - -import { Component, forwardRef, Input, OnInit } 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, - DeviceTransportType, Lwm2mDeviceProfileTransportConfiguration -} from '@shared/models/device.models'; - -@Component({ - selector: 'tb-lwm2m-device-profile-transport-configuration', - templateUrl: './lwm2m-device-profile-transport-configuration.component.html', - styleUrls: [], - providers: [{ - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => Lwm2mDeviceProfileTransportConfigurationComponent), - multi: true - }] -}) -export class Lwm2mDeviceProfileTransportConfigurationComponent implements ControlValueAccessor, OnInit { - - lwm2mDeviceProfileTransportConfigurationFormGroup: FormGroup; - - private requiredValue: boolean; - get required(): boolean { - return this.requiredValue; - } - @Input() - set required(value: boolean) { - this.requiredValue = coerceBooleanProperty(value); - } - - @Input() - disabled: boolean; - - private propagateChange = (v: any) => { }; - - constructor(private store: Store, - private fb: FormBuilder) { - } - - registerOnChange(fn: any): void { - this.propagateChange = fn; - } - - registerOnTouched(fn: any): void { - } - - ngOnInit() { - this.lwm2mDeviceProfileTransportConfigurationFormGroup = this.fb.group({ - configuration: [null, Validators.required] - }); - this.lwm2mDeviceProfileTransportConfigurationFormGroup.valueChanges.subscribe(() => { - this.updateModel(); - }); - } - - setDisabledState(isDisabled: boolean): void { - this.disabled = isDisabled; - if (this.disabled) { - this.lwm2mDeviceProfileTransportConfigurationFormGroup.disable({emitEvent: false}); - } else { - this.lwm2mDeviceProfileTransportConfigurationFormGroup.enable({emitEvent: false}); - } - } - - writeValue(value: Lwm2mDeviceProfileTransportConfiguration | null): void { - this.lwm2mDeviceProfileTransportConfigurationFormGroup.patchValue({configuration: value}, {emitEvent: false}); - } - - private updateModel() { - let configuration: DeviceProfileTransportConfiguration = null; - if (this.lwm2mDeviceProfileTransportConfigurationFormGroup.valid) { - configuration = this.lwm2mDeviceProfileTransportConfigurationFormGroup.getRawValue().configuration; - // configuration.type = DeviceTransportType.LWM2M; - } - this.propagateChange(configuration); - } -} diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html new file mode 100644 index 0000000000..0e10a8e843 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html @@ -0,0 +1,120 @@ + +
+
+
+
+ + {{ 'device-profile.lwm2m.mode' | translate }} + + + {{ credentialTypeLwM2MNamesMap.get(securityConfigLwM2MType[securityMode]) }} + + + + + {{ 'device-profile.lwm2m.server-host' | translate }} + + + {{ 'device-profile.lwm2m.server-host' | translate }} + {{ 'device-profile.lwm2m.required' | translate }} + + + + {{ 'device-profile.lwm2m.server-port' | translate }} + + + {{ 'device-profile.lwm2m.server-port' | translate }} + {{ 'device-profile.lwm2m.required' | translate }} + + + + {{ 'device-profile.lwm2m.short-id' | translate }} + + + {{ 'device-profile.lwm2m.short-id' | translate }} + {{ 'device-profile.lwm2m.required' | translate }} + + +
+
+
+
+ + {{ 'device-profile.lwm2m.client-hold-off-time' | translate }} + + + {{ 'device-profile.lwm2m.client-hold-off-time' | translate }} + {{ 'device-profile.lwm2m.required' | translate }} + + + + {{ 'device-profile.lwm2m.bootstrap-server-account-timeout' | translate }} + + + {{ 'device-profile.lwm2m.bootstrap-server-account-timeout' | translate }} + {{ 'device-profile.lwm2m.required' | translate }} + + + + {{ 'device-profile.lwm2m.bootstrap-server' | translate }} + +
+
+
+ + {{ 'device-profile.lwm2m.server-public-key' | translate }} + + {{serverPublicKey.value?.length || 0}}/{{lenMaxServerPublicKey}} + + {{ 'device-profile.lwm2m.server-public-key' | translate }} + {{ 'device-profile.lwm2m.required' | translate }} + + + {{ 'device-profile.lwm2m.client-key' | translate }} + {{ 'device-profile.lwm2m.pattern_hex_dec_182' | translate }} + + + {{ 'device-profile.lwm2m.client-key' | translate }} + {{ 'device-profile.lwm2m.pattern_hex_dec' | translate }} + + +
+
+
+
+
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts new file mode 100644 index 0000000000..9f1fed9bc9 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts @@ -0,0 +1,223 @@ +/// +/// Copyright © 2016-2020 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component, forwardRef, Inject, Input, OnInit } from "@angular/core"; + +import { + ControlValueAccessor, + FormBuilder, FormGroup, NG_VALUE_ACCESSOR, NgModel, Validators +} from "@angular/forms"; +import { + SECURITY_CONFIG_MODE, + SECURITY_CONFIG_MODE_NAMES, + KEY_PUBLIC_REGEXP_PSK, + ServerSecurityConfig, + LEN_MAX_PUBLIC_KEY_PSK, + LEN_MAX_PUBLIC_KEY_RPK_X509, + KEY_PUBLIC_REGEXP_X509, + DEFAULT_PORT_BOOTSTRAP_NO_SEC, + DEFAULT_PORT_SERVER_NO_SEC, + DEFAULT_CLIENT_HOLD_OFF_TIME, + DEFAULT_ID_SERVER +} from "./profile-config.models"; +import { Store } from "@ngrx/store"; +import { AppState } from "@core/core.state"; +import { coerceBooleanProperty } from "@angular/cdk/coercion"; +import { WINDOW } from "../../../../../../core/services/window.service"; +import { pairwise, startWith } from 'rxjs/operators'; +import { DeviceProfileService } from '@core/http/device-profile.service'; + +@Component({ + selector: 'tb-profile-lwm2m-device-config-server', + templateUrl: './lwm2m-device-config-server.component.html', + styleUrls: [], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => Lwm2mDeviceConfigServerComponent), + multi: true + } + ] +}) + +export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAccessor, Validators { + + valuePrev = null as any; + private requiredValue: boolean; + serverFormGroup: FormGroup; + securityConfigLwM2MType = SECURITY_CONFIG_MODE; + securityConfigLwM2MTypes = Object.keys(SECURITY_CONFIG_MODE); + credentialTypeLwM2MNamesMap = SECURITY_CONFIG_MODE_NAMES; + lenMaxServerPublicKey = LEN_MAX_PUBLIC_KEY_PSK; + currentSecurityMode = null; + + + @Input() + disabled: boolean; + + @Input() + bootstrapServerIs: boolean + + get required(): boolean { + return this.requiredValue; + } + + @Input() + set required(value: boolean) { + this.requiredValue = coerceBooleanProperty(value); + } + + constructor(protected store: Store, + public fb: FormBuilder, + private deviceProfileService: DeviceProfileService, + @Inject(WINDOW) private window: Window) { + this.serverFormGroup = this.getServerGroup(); + this.serverFormGroup.get('securityMode').valueChanges.pipe( + startWith(null), + pairwise() + ).subscribe(([previousValue, currentValue]) => { + if (previousValue === null || previousValue !== currentValue) { + this.getLwm2mBootstrapSecurityInfo(currentValue); + this.updateValidate(currentValue); + this.serverFormGroup.updateValueAndValidity(); + } + + }); + this.serverFormGroup.valueChanges.subscribe(value => { + if (this.disabled !== undefined && !this.disabled) { + this.propagateChangeState(value); + } + }); + } + + ngOnInit(): void { + } + + updateValueFields(serverData: ServerSecurityConfig): void { + serverData['bootstrapServerIs'] = this.bootstrapServerIs; + this.serverFormGroup.patchValue(serverData, {emitEvent: false}); + this.serverFormGroup.get('bootstrapServerIs').disable(); + const securityMode = this.serverFormGroup.get('securityMode').value as SECURITY_CONFIG_MODE; + this.updateValidate(securityMode); + } + + updateValidate(securityMode: SECURITY_CONFIG_MODE): void { + switch (securityMode) { + case SECURITY_CONFIG_MODE.NO_SEC: + this.serverFormGroup.get('serverPublicKey').setValidators([]); + break; + case SECURITY_CONFIG_MODE.PSK: + this.lenMaxServerPublicKey = LEN_MAX_PUBLIC_KEY_PSK; + this.serverFormGroup.get('serverPublicKey').setValidators([]); + break; + case SECURITY_CONFIG_MODE.RPK: + this.lenMaxServerPublicKey = LEN_MAX_PUBLIC_KEY_RPK_X509; + this.serverFormGroup.get('serverPublicKey').setValidators([Validators.required, Validators.pattern(KEY_PUBLIC_REGEXP_PSK)]); + break; + case SECURITY_CONFIG_MODE.X509: + this.lenMaxServerPublicKey = LEN_MAX_PUBLIC_KEY_RPK_X509; + this.serverFormGroup.get('serverPublicKey').setValidators([Validators.required, Validators.pattern(KEY_PUBLIC_REGEXP_X509)]); + break; + } + this.checkValueWithNewValidate(); + } + + checkValueWithNewValidate(): void { + this.serverFormGroup.patchValue({ + host: this.serverFormGroup.get('host').value, + port: this.serverFormGroup.get('port').value, + bootstrapServerIs: this.serverFormGroup.get('bootstrapServerIs').value, + serverPublicKey: this.serverFormGroup.get('serverPublicKey').value, + clientHoldOffTime: this.serverFormGroup.get('clientHoldOffTime').value, + serverId: this.serverFormGroup.get('serverId').value, + bootstrapServerAccountTimeout: this.serverFormGroup.get('bootstrapServerAccountTimeout').value, + }, + {emitEvent: true}); + } + + writeValue(value: any): void { + if (value) { + this.updateValueFields(value); + } + } + + private propagateChange = (v: any) => { + }; + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + private propagateChangeState(value: any): void { + if (value !== undefined) { + if (this.valuePrev === null) { + this.valuePrev = "init"; + } else if (this.valuePrev === "init") { + this.valuePrev = value; + } else if (JSON.stringify(value) !== JSON.stringify(this.valuePrev)) { + this.valuePrev = value; + if (this.serverFormGroup.valid) { + this.propagateChange(value); + } else { + this.propagateChange(null); + } + } + } + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + this.valuePrev = null; + if (isDisabled) { + this.serverFormGroup.disable({emitEvent: false}); + } else { + this.serverFormGroup.enable({emitEvent: false}); + } + } + + registerOnTouched(fn: any): void { + } + + getServerGroup(): FormGroup { + const port = (this.bootstrapServerIs) ? DEFAULT_PORT_BOOTSTRAP_NO_SEC : DEFAULT_PORT_SERVER_NO_SEC; + return this.fb.group({ + host: [this.window.location.hostname, this.required ? [Validators.required] : []], + port: [port, this.required ? [Validators.required] : []], + bootstrapServerIs: [this.bootstrapServerIs, []], + securityMode: [this.fb.control(SECURITY_CONFIG_MODE.NO_SEC), []], + serverPublicKey: ['', this.required ? [Validators.required] : []], + clientHoldOffTime: [DEFAULT_CLIENT_HOLD_OFF_TIME, this.required ? [Validators.required] : []], + serverId: [DEFAULT_ID_SERVER, this.required ? [Validators.required] : []], + bootstrapServerAccountTimeout: ['', this.required ? [Validators.required] : []], + }) + } + + getLwm2mBootstrapSecurityInfo(mode: string) { + this.deviceProfileService.getLwm2mBootstrapSecurityInfo(mode, this.serverFormGroup.get('bootstrapServerIs').value).subscribe( + (serverSecurityConfig) => { + this.serverFormGroup.patchValue({ + host: serverSecurityConfig.host, + port: serverSecurityConfig.port, + serverPublicKey: serverSecurityConfig.serverPublicKey, + clientHoldOffTime: serverSecurityConfig.clientHoldOffTime, + serverId: serverSecurityConfig.serverId, + bootstrapServerAccountTimeout: serverSecurityConfig.bootstrapServerAccountTimeout + }, + {emitEvent: true}); + } + ); + } +} diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html new file mode 100644 index 0000000000..846f991e3e --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html @@ -0,0 +1,140 @@ + +
+
+ + +
+ + +
+
+ + +
+
+ +
+ + + + +
{{ 'device-profile.lwm2m.servers' | translate | uppercase }}
+
+
+
+
+ + {{ 'device-profile.lwm2m.short-id' | translate }} + + + {{ 'device-profile.lwm2m.short-id' | translate }} + {{ 'device-profile.lwm2m.required' | translate }} + + + + {{ 'device-profile.lwm2m.lifetime' | translate }} + + + {{ 'device-profile.lwm2m.lifetime' | translate }} + {{ 'device-profile.lwm2m.required' | translate }} + + +
+
+ + {{ 'device-profile.lwm2m.default-min-period' | translate }} + + + {{ 'device-profile.lwm2m.default-min-period' | translate }} + {{ 'device-profile.lwm2m.required' | translate }} + + + + {{ 'device-profile.lwm2m.binding' | translate }} + + + {{ 'device-profile.lwm2m.binding' | translate }} + {{ 'device-profile.lwm2m.required' | translate }} + + +
+
+ + {{ 'device-profile.lwm2m.notif-if-disabled' | translate }} + +
+
+
+
+ + + + +
{{ 'device-profile.lwm2m.bootstrap-server' | translate | uppercase }}
+
+
+
+ + +
+
+
+ + + + +
{{ 'device-profile.lwm2m.lwm2m-server' | translate | uppercase }}
+
+
+
+ + +
+
+
+
+
+ +
+ + +
+
+
+
+
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts new file mode 100644 index 0000000000..d724a25332 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts @@ -0,0 +1,541 @@ +/// +/// Copyright © 2016-2020 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { + DeviceProfileTransportConfiguration, + DeviceTransportType +} from '@shared/models/device.models'; +import { + Component, + forwardRef, Inject, + Input, + OnInit +} 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 { + ATTR, + OBSERVE, + OBSERVE_ATTR, + TELEMETRY, + ObjectLwM2M, getDefaultProfileConfig, KEY_NAME, Instance +} from "./profile-config.models"; +import { DeviceProfileService } from "../../../../../../core/http/device-profile.service"; +import { deepClone, isUndefined } from "../../../../../../core/utils"; +import { WINDOW } from "../../../../../../core/services/window.service"; +import { JsonObject } from '@angular/compiler-cli/ngcc/src/packages/entry_point'; +import { isNotNullOrUndefined } from 'codelyzer/util/isNotNullOrUndefined'; + +@Component({ + selector: 'tb-profile-lwm2m-device-transport-configuration', + templateUrl: './lwm2m-device-profile-transport-configuration.component.html', + styleUrls: [], + providers: [{ + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => Lwm2mDeviceProfileTransportConfigurationComponent), + multi: true + }] +}) +export class Lwm2mDeviceProfileTransportConfigurationComponent implements ControlValueAccessor, OnInit, Validators { + + lwm2mDeviceProfileTransportConfFormGroup: FormGroup; + observeAttr = OBSERVE_ATTR as string; + observe = OBSERVE as string; + attribute = ATTR as string; + telemetry = TELEMETRY as string; + keyName = KEY_NAME as string; + bootstrapServers: string; + bootstrapServer: string; + lwm2mServer: string; + private configurationValue: {}; + private requiredValue: boolean; + private disabled = false as boolean; + sortFunction = this.sortObjectKeyPathJson; + + get required(): boolean { + return this.requiredValue; + } + + @Input() + set required(value: boolean) { + this.requiredValue = coerceBooleanProperty(value); + } + + private propagateChange = (v: any) => { + }; + + constructor(private store: Store, + private fb: FormBuilder, + private deviceProfileService: DeviceProfileService, + @Inject(WINDOW) private window: Window) { + this.lwm2mDeviceProfileTransportConfFormGroup = this.fb.group({ + objectIds: [{}, Validators.required], + observeAttrTelemetry: [{'clientLwM2M': [] as ObjectLwM2M []}, Validators.required], + shortId: [null, Validators.required], + lifetime: [null, Validators.required], + defaultMinPeriod: [null, Validators.required], + notifIfDisabled: [true, []], + binding: ["U", Validators.required], + bootstrapServer: [null, Validators.required], + lwm2mServer: [null, Validators.required], + configurationJson: [null, Validators.required], + }); + this.lwm2mDeviceProfileTransportConfFormGroup.valueChanges.subscribe(value => { + if (!this.disabled) { + this.updateModel(); + } + }); + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + ngOnInit() { + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + if (isDisabled) { + this.lwm2mDeviceProfileTransportConfFormGroup.disable({emitEvent: false}); + } else { + this.lwm2mDeviceProfileTransportConfFormGroup.enable({emitEvent: false}); + } + } + + writeValue(value: any | null): void { + value = (Object.keys(value).length == 0) ? getDefaultProfileConfig() : value; + this.lwm2mDeviceProfileTransportConfFormGroup.patchValue({ + configurationJson: value + }, + {emitEvent: false}); + this.configurationValue = this.lwm2mDeviceProfileTransportConfFormGroup.getRawValue().configurationJson; + this.initWriteValue(); + } + + private initWriteValue(): void { + let modelValue = {"objectIds": null, "objectsList": []}; + modelValue.objectIds = this.getObjectsFromJsonAllConfig(); + if (modelValue.objectIds !== null) { + this.deviceProfileService.getLwm2mObjects(modelValue.objectIds).subscribe( + (objectsList) => { + modelValue.objectsList = objectsList; + this.updateWriteValue(modelValue); + } + ); + } else { + this.updateWriteValue(modelValue); + } + } + + private updateWriteValue(value: any): void { + let objectsList = deepClone(value.objectsList); + this.lwm2mDeviceProfileTransportConfFormGroup.patchValue({ + objectIds: value, + observeAttrTelemetry: {clientLwM2M: this.getObserveAttrTelemetryObjects(objectsList)}, + shortId: this.configurationValue['bootstrap'].servers.shortId, + lifetime: this.configurationValue['bootstrap'].servers.lifetime, + defaultMinPeriod: this.configurationValue['bootstrap'].servers.defaultMinPeriod, + notifIfDisabled: this.configurationValue['bootstrap'].servers.notifIfDisabled, + binding: this.configurationValue['bootstrap'].servers.binding, + bootstrapServer: this.configurationValue['bootstrap'].bootstrapServer, + lwm2mServer: this.configurationValue['bootstrap'].lwm2mServer + }, + {emitEvent: false}); + } + + private updateModel() { + let configuration: DeviceProfileTransportConfiguration = null; + if (this.lwm2mDeviceProfileTransportConfFormGroup.valid) { + this.upDateValueToJson(); + configuration = this.lwm2mDeviceProfileTransportConfFormGroup.getRawValue().configurationJson; + configuration.type = DeviceTransportType.LWM2M; + } + this.propagateChange(configuration); + } + + private updateObserveAttrTelemetryObjectFormGroup(objectsList: ObjectLwM2M[]) { + this.lwm2mDeviceProfileTransportConfFormGroup.patchValue({ + observeAttrTelemetry: {clientLwM2M: this.getObserveAttrTelemetryObjects(objectsList)} + }, + {emitEvent: false}); + this.lwm2mDeviceProfileTransportConfFormGroup.get("observeAttrTelemetry").markAsPristine({ + onlySelf: true + }); + } + + upDateValueToJson(): void { + this.upDateValueToJsonTab_0(); + this.upDateValueToJsonTab_1(); + } + + upDateValueToJsonTab_0(): void { + if (!this.lwm2mDeviceProfileTransportConfFormGroup.get("observeAttrTelemetry").pristine) { + this.upDateObserveAttrTelemetryFromGroupToJson(this.lwm2mDeviceProfileTransportConfFormGroup.get("observeAttrTelemetry").value['clientLwM2M']); + this.lwm2mDeviceProfileTransportConfFormGroup.get("observeAttrTelemetry").markAsPristine({ + onlySelf: true + }); + this.upDateJsonAllConfig(); + } + } + + upDateValueToJsonTab_1(): void { + this.upDateValueServersToJson(); + if (!this.lwm2mDeviceProfileTransportConfFormGroup.get('bootstrapServer').pristine) { + this.configurationValue['bootstrap'].bootstrapServer = this.lwm2mDeviceProfileTransportConfFormGroup.get('bootstrapServer').value; + this.lwm2mDeviceProfileTransportConfFormGroup.get('bootstrapServer').markAsPristine({ + onlySelf: true + }); + this.upDateJsonAllConfig(); + } + if (!this.lwm2mDeviceProfileTransportConfFormGroup.get('lwm2mServer').pristine) { + this.configurationValue['bootstrap'].lwm2mServer = this.lwm2mDeviceProfileTransportConfFormGroup.get('lwm2mServer').value; + this.lwm2mDeviceProfileTransportConfFormGroup.get('lwm2mServer').markAsPristine({ + onlySelf: true + }); + this.upDateJsonAllConfig(); + } + } + + upDateValueServersToJson(): void { + if (!this.lwm2mDeviceProfileTransportConfFormGroup.get('shortId').pristine) { + this.configurationValue['bootstrap'].servers.shortId = this.lwm2mDeviceProfileTransportConfFormGroup.get('shortId').value; + this.lwm2mDeviceProfileTransportConfFormGroup.get('shortId').markAsPristine({ + onlySelf: true + }); + this.upDateJsonAllConfig(); + } + if (!this.lwm2mDeviceProfileTransportConfFormGroup.get('lifetime').pristine) { + this.configurationValue['bootstrap'].servers.lifetime = this.lwm2mDeviceProfileTransportConfFormGroup.get('lifetime').value; + this.lwm2mDeviceProfileTransportConfFormGroup.get('lifetime').markAsPristine({ + onlySelf: true + }); + this.upDateJsonAllConfig(); + } + if (!this.lwm2mDeviceProfileTransportConfFormGroup.get('defaultMinPeriod').pristine) { + this.configurationValue['bootstrap'].servers.defaultMinPeriod = this.lwm2mDeviceProfileTransportConfFormGroup.get('defaultMinPeriod').value; + this.lwm2mDeviceProfileTransportConfFormGroup.get('defaultMinPeriod').markAsPristine({ + onlySelf: true + }); + this.upDateJsonAllConfig(); + } + if (!this.lwm2mDeviceProfileTransportConfFormGroup.get('notifIfDisabled').pristine) { + this.configurationValue['bootstrap'].servers.notifIfDisabled = this.lwm2mDeviceProfileTransportConfFormGroup.get('notifIfDisabled').value; + this.lwm2mDeviceProfileTransportConfFormGroup.get('notifIfDisabled').markAsPristine({ + onlySelf: true + }); + this.upDateJsonAllConfig(); + } + if (!this.lwm2mDeviceProfileTransportConfFormGroup.get('binding').pristine) { + this.configurationValue['bootstrap'].servers.binding = this.lwm2mDeviceProfileTransportConfFormGroup.get('binding').value; + this.lwm2mDeviceProfileTransportConfFormGroup.get('binding').markAsPristine({ + onlySelf: true + }); + this.upDateJsonAllConfig(); + } + } + + getObserveAttrTelemetryObjects(listObject: ObjectLwM2M[]): ObjectLwM2M [] { + let clientObserveAttr = deepClone(listObject) as ObjectLwM2M[]; + if (this.configurationValue[this.observeAttr]) { + let observeArray = this.configurationValue[this.observeAttr][this.observe] as Array; + let attributeArray = this.configurationValue[this.observeAttr][this.attribute] as Array; + let telemetryArray = this.configurationValue[this.observeAttr][this.telemetry] as Array; + let keyNameJson = this.configurationValue[this.observeAttr][this.keyName] as JsonObject; + if (this.includesInstancesNo(attributeArray, telemetryArray, clientObserveAttr)) { + this.addInstances(attributeArray, telemetryArray, clientObserveAttr); + } + if (observeArray) this.updateObserveAttrTelemetryObjects(observeArray, clientObserveAttr, "observe"); + if (attributeArray) this.updateObserveAttrTelemetryObjects(attributeArray, clientObserveAttr, "attribute"); + if (telemetryArray) this.updateObserveAttrTelemetryObjects(telemetryArray, clientObserveAttr, "telemetry"); + if (keyNameJson) this.updateKeyNameObjects(deepClone(keyNameJson), clientObserveAttr); + } + clientObserveAttr.forEach(obj => { + obj.instances.sort((a,b) => a.id - b.id);; + }) + return clientObserveAttr; + } + + includesInstancesNo(attributeArray: Array, telemetryArray: Array, clientObserveAttr: ObjectLwM2M[]): boolean { + let isIdIndex = (element) => !element.includes("/0/"); + return attributeArray.findIndex(isIdIndex) >= 0 || telemetryArray.findIndex(isIdIndex) >= 0 + + } + + addInstances(attributeArray: Array, telemetryArray: Array, clientObserveAttr: ObjectLwM2M[]): void { + let attr = [] as Array; + [...attributeArray].filter(x => (!x.includes("/0/"))).forEach(x => { + attr.push(this.convertPathToInstance(x)); + }); + let telemetry = [] as Array; + [...telemetryArray].filter(x => (!x.includes("/0/"))).forEach(x => { + telemetry.push(this.convertPathToInstance(x)); + }); + let instancesNoZero = new Set(attr.concat(telemetry).sort()); + instancesNoZero.forEach(path => { + let pathParameter = Array.from(path.split('/'), Number); + let objectLwM2M = clientObserveAttr.find(x => (x.id === pathParameter[0])); + if (objectLwM2M) { + let instance = deepClone(objectLwM2M.instances[0]) as Instance; + instance.id = pathParameter[1]; + objectLwM2M.instances.push(instance); + } + }) + } + + convertPathToInstance(path: string): string { + let newX = Array.from(path.substring(1).split('/'), Number); + return [newX[0], newX[1]].join("/"); + } + + updateObserveAttrTelemetryObjects(isParameter: Array, clientObserveAttr: ObjectLwM2M[], nameParameter: string): void { + isParameter.forEach(attr => { + let idKeys = Array.from(attr.substring(1).split('/'), Number); + clientObserveAttr + .forEach(e => { + if (e.id == idKeys[0]) { + let instance = e.instances.find(e => e.id == idKeys[1]); + if (isNotNullOrUndefined(instance)) { + instance.resources.find(e => e.id == idKeys[2])[nameParameter] = true; + } + } + }); + }); + } + + updateKeyNameObjects(nameJson: JsonObject, clientObserveAttr: ObjectLwM2M[]): void { + let keyName = JSON.parse(JSON.stringify(nameJson)); + Object.keys(keyName).forEach(function (key) { + let idKeys = Array.from(key.substring(1).split('/'), Number); + clientObserveAttr + .forEach(e => { + if (e.id == idKeys[0]) { + e.instances.find(e => e.id == idKeys[1]).resources + .find(e => e.id == idKeys[2]).keyName = keyName[key]; + } + }); + }); + } + + upDateObserveAttrTelemetryFromGroupToJson(val: ObjectLwM2M []): void { + let observeArray = [] as Array; + let attributeArray = [] as Array; + let telemetryArray = [] as Array; + let observeJson = JSON.parse(JSON.stringify(val)); + let pathObj; + let pathInst; + let pathRes + observeJson.forEach(obj => { + Object.entries(obj).forEach(([key, value]) => { + if (key === 'id') { + pathObj = value; + } + if (key === 'instances') { + let instancesJson = JSON.parse(JSON.stringify(value)) as []; + if (instancesJson.length > 0) { + instancesJson.forEach(instance => { + Object.entries(instance).forEach(([key, value]) => { + if (key === 'id') { + pathInst = value; + } + if (key === 'resources') { + let resourcesJson = JSON.parse(JSON.stringify(value)) as []; + if (resourcesJson.length > 0) { + resourcesJson.forEach(res => { + Object.entries(res).forEach(([key, value]) => { + if (key === 'id') { + // pathRes = value + pathRes = '/' + pathObj + '/' + pathInst + '/' + value; + } else if (key === 'observe' && value) { + observeArray.push(pathRes) + } else if (key === 'attribute' && value) { + attributeArray.push(pathRes) + } else if (key === 'telemetry' && value) { + telemetryArray.push(pathRes) + } + }); + }); + } + } + }); + }); + } + } + }); + }); + if (isUndefined(this.configurationValue[this.observeAttr])) { + this.configurationValue[this.observeAttr] = { + [this.observe]: observeArray, + [this.attribute]: attributeArray, + [this.telemetry]: telemetryArray + }; + } else { + this.configurationValue[this.observeAttr][this.observe] = observeArray; + this.configurationValue[this.observeAttr][this.attribute] = attributeArray; + this.configurationValue[this.observeAttr][this.telemetry] = telemetryArray; + } + this.updateKeyName(); + } + + sortObjectKeyPathJson(key, value) { + if (key == "keyName") { + return Object.keys(value).sort((a, b) => { + let aLC = Array.from(a.substring(1).split('/'), Number); + let bLC = Array.from(b.substring(1).split('/'), Number); + return aLC[0] == bLC[0] ? aLC[1] - bLC[1] : aLC[0] - bLC[0]; + }).reduce((r, k) => (r[k] = value[k], r), {}); + } else { + return value + } + } + + updateKeyName(): void { + let paths = new Set(); + if (this.configurationValue[this.observeAttr][this.attribute]) { + this.configurationValue[this.observeAttr][this.attribute].forEach(path => { + paths.add(path); + }); + } + if (this.configurationValue[this.observeAttr][this.telemetry]) { + this.configurationValue[this.observeAttr][this.telemetry].forEach(path => { + paths.add(path); + }); + } + let keyNameNew = {}; + paths.forEach(path => { + let pathParameter = this.findIndexsForIds(path); + if (pathParameter.length === 3) { + let value = this.lwm2mDeviceProfileTransportConfFormGroup.get("observeAttrTelemetry").value['clientLwM2M'][pathParameter[0]].instances[pathParameter[1]].resources[pathParameter[2]][this.keyName]; + keyNameNew[path] = value; + } + }); + this.configurationValue[this.observeAttr][this.keyName] = this.sortObjectKeyPathJson("keyName", keyNameNew); + } + + findIndexsForIds(path: string): number[] { + let pathParameter = Array.from(path.substring(1).split('/'), Number); + let pathParameterIndexes = [] as number[]; + let objectsOld = deepClone(this.lwm2mDeviceProfileTransportConfFormGroup.get("observeAttrTelemetry").value.clientLwM2M) as ObjectLwM2M[]; + let isIdIndex = (element) => element.id === pathParameter[0]; + let objIndex = objectsOld.findIndex(isIdIndex); + if (objIndex >= 0) { + pathParameterIndexes.push(objIndex); + isIdIndex = (element) => element.id === pathParameter[1]; + let instIndex = objectsOld[objIndex].instances.findIndex(isIdIndex); + if (instIndex >= 0) { + pathParameterIndexes.push(instIndex); + isIdIndex = (element) => element.id === pathParameter[2]; + let resIndex = objectsOld[objIndex].instances[instIndex].resources.findIndex(isIdIndex); + if (resIndex >= 0) { + pathParameterIndexes.push(resIndex); + } + } + } + return pathParameterIndexes; + } + + getObjectsFromJsonAllConfig(): number [] { + let objectsIds = new Set(); + if (this.configurationValue[this.observeAttr]) { + if (this.configurationValue[this.observeAttr][this.observe]) { + this.configurationValue[this.observeAttr][this.observe].forEach(obj => { + objectsIds.add(Array.from(obj.substring(1).split('/'), Number)[0]); + }); + } + if (this.configurationValue[this.observeAttr][this.attribute]) { + this.configurationValue[this.observeAttr][this.attribute].forEach(obj => { + objectsIds.add(Array.from(obj.substring(1).split('/'), Number)[0]); + }); + } + if (this.configurationValue[this.observeAttr][this.telemetry]) { + this.configurationValue[this.observeAttr][this.telemetry].forEach(obj => { + objectsIds.add(Array.from(obj.substring(1).split('/'), Number)[0]); + }); + } + } + return (objectsIds.size > 0) ? Array.from(objectsIds) : null; + } + + upDateJsonAllConfig(): void { + this.lwm2mDeviceProfileTransportConfFormGroup.patchValue({ + configurationJson: this.configurationValue + }, {emitEvent: false}); + this.lwm2mDeviceProfileTransportConfFormGroup.markAsPristine({ + onlySelf: true + }); + } + + addObjectsList(value: ObjectLwM2M[]): void { + this.updateObserveAttrTelemetryObjectFormGroup(deepClone(value)); + } + + removeObjectsList(value: ObjectLwM2M): void { + let objectsOld = deepClone(this.lwm2mDeviceProfileTransportConfFormGroup.get("observeAttrTelemetry").value.clientLwM2M); + const isIdIndex = (element) => element.id === value.id; + let index = objectsOld.findIndex(isIdIndex); + if (index >= 0) { + objectsOld.splice(index, 1); + } + this.updateObserveAttrTelemetryObjectFormGroup(objectsOld); + this.removeObserveAttrTelemetryFromJson(this.observe, value.id); + this.removeObserveAttrTelemetryFromJson(this.telemetry, value.id); + this.removeObserveAttrTelemetryFromJson(this.attribute, value.id); + this.removeObserveAttrTelemetryFromJson(this.attribute, value.id); + this.removeKeyNameFromJson(value.id); + this.upDateJsonAllConfig(); + } + + removeObserveAttrTelemetryFromJson(observeAttrTel: string, id: number): void { + let isIdIndex = (element) => Array.from(element.substring(1).split('/'), Number)[0] === id; + let index = this.configurationValue[this.observeAttr][observeAttrTel].findIndex(isIdIndex); + while (index >= 0) { + this.configurationValue[this.observeAttr][observeAttrTel].splice(index, 1); + index = this.configurationValue[this.observeAttr][observeAttrTel].findIndex(isIdIndex); + } + } + + removeKeyNameFromJson(id: number): void { + let keyNmaeJson = this.configurationValue[this.observeAttr][this.keyName]; + Object.keys(keyNmaeJson).forEach(function (key) { + let idKey = Array.from(key.substring(1).split('/'), Number)[0]; + if (idKey === id) { + delete keyNmaeJson[key]; + } + }); + } + + isPathInJson(path: string): boolean { + let isPath = this.findPathInJson(path, this.attribute); + if (!isPath) { + isPath = this.findPathInJson(path, this.telemetry); + } + return (isPath) ? true : false; + } + + findPathInJson(path: string, side: string): string { + if (this.configurationValue[this.observeAttr]) { + if (this.configurationValue[this.observeAttr][side]) { + return this.configurationValue[this.observeAttr][side].find( + pathJs => pathJs === path); + } + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.html new file mode 100644 index 0000000000..cddc6f1ef5 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.html @@ -0,0 +1,57 @@ + + + {{ 'device-profile.lwm2m.instances-list' | translate }} + + + {{instanceIdInputFor}} + close + + + {{ 'device-profile.lwm2m.instances-input' | translate }} + + + {{ translate.get('device-profile.lwm2m.valid-id-instance-no-min', { + instance: instanceIdInput.value.toString(), min: instanceIdValueMin.toString() + }) | async }} + + + {{ translate.get('device-profile.lwm2m.valid-id-instance-no-max', { + instance: instanceIdInput.value.toString(), max: instanceIdValueMax.toString() + }) | async }} + + + {{ translate.get('device-profile.lwm2m.instances-input-holder', { + instance: instanceIdInput.value.toString(), max: instanceIdValueMax.toString() + }) | async }} + + + + + diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.scss b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.scss new file mode 100644 index 0000000000..45e601db09 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.scss @@ -0,0 +1,22 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +:host ::ng-deep { + mat-form-field.lwm2m-instances-list { + & > .mat-form-field-wrapper > .mat-form-field-underline { + display: none; + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.ts new file mode 100644 index 0000000000..20a72d8dcd --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.ts @@ -0,0 +1,179 @@ +/// +/// Copyright © 2016-2020 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { + Component, + forwardRef, + Input, + OnInit, + ViewChild, + ElementRef, +} from "@angular/core"; +import { + ControlValueAccessor, + FormBuilder, + FormGroup, NG_VALIDATORS, + NG_VALUE_ACCESSOR, Validators +} from "@angular/forms"; +import { coerceBooleanProperty } from "@angular/cdk/coercion"; +import { Store } from "@ngrx/store"; +import { AppState } from "../../../../../../core/core.state"; +import { MatChipList } from '@angular/material/chips'; +import { + INSTANCES_ID_VALUE_MAX, + INSTANCES_ID_VALUE_MIN +} from "./profile-config.models"; +import { TranslateService } from "@ngx-translate/core"; +import { DeviceProfileService } from "../../../../../../core/http/device-profile.service"; + +@Component({ + selector: 'tb-profile-lwm2m-object-add-instances-list', + templateUrl: './lwm2m-object-add-instances-list.component.html', + styleUrls: ['./lwm2m-object-add-instances-list.component.scss'], + providers: [{ + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => Lwm2mObjectAddInstancesListComponent), + multi: true + }] +}) +export class Lwm2mObjectAddInstancesListComponent implements ControlValueAccessor, OnInit, Validators { + + lwm2mObjectListFormGroup: FormGroup; + private requiredValue: boolean; + private instancesIdsList: Set | null; + filteredObjectsList: Array; + private disabled = false as boolean; + private dirty = false as boolean; + instanceIdValueMin = INSTANCES_ID_VALUE_MIN as number + instanceIdValueMax = INSTANCES_ID_VALUE_MAX as number + + get required(): boolean { + return this.requiredValue; + } + + @Input() + set required(value: boolean) { + const newVal = coerceBooleanProperty(value); + if (this.requiredValue !== newVal) { + this.requiredValue = newVal; + this.updateValidators(); + } + } + + @ViewChild('instanceIdInput') instanceIdInput: ElementRef; + @ViewChild('chipList', {static: true}) chipList: MatChipList; + + private propagateChange = (v: any) => { + }; + + constructor(private store: Store, + public translate: TranslateService, + private deviceProfileService: DeviceProfileService, + private fb: FormBuilder) { + this.lwm2mObjectListFormGroup = this.fb.group({ + instancesIdsList: [null], + instanceIdInput: [null] + }); + } + + updateValidators() { + this.lwm2mObjectListFormGroup.get('instanceIdInput').setValidators([ + Validators.min(this.instanceIdValueMin), + Validators.max(this.instanceIdValueMax)]); + this.lwm2mObjectListFormGroup.get('instanceIdInput').updateValueAndValidity(); + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + ngOnInit() { + } + + ngAfterViewInit(): void { + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + if (isDisabled) { + this.lwm2mObjectListFormGroup.disable({emitEvent: false}); + } else { + this.lwm2mObjectListFormGroup.enable({emitEvent: false}); + } + } + + writeValue(value: Set): void { + this.instancesIdsList = new Set(); + if (value && value.size) { + value.forEach(item => this.instancesIdsList.add(item)); + this.lwm2mObjectListFormGroup.get('instancesIdsList').setValue(this.instancesIdsList); + } + this.updateValidators(); + this.dirty = false; + } + + add(value: number): void { + if (!isNaN(value) && this.lwm2mObjectListFormGroup.get('instanceIdInput').valid) { + this.instancesIdsList.add(value); + this.lwm2mObjectListFormGroup.get('instancesIdsList').setValue(this.instancesIdsList); + this.propagateChange(this.instancesIdsList); + this.dirty = true + } + this.clear(); + } + + remove(object: number) { + this.instancesIdsList.delete(object); + this.lwm2mObjectListFormGroup.get('instancesIdsList').setValue(this.instancesIdsList); + this.propagateChange(this.instancesIdsList); + this.dirty = true + this.clear(); + } + + displayFn(object?: number): number | undefined { + return object ? object : undefined; + } + + clear() { + this.lwm2mObjectListFormGroup.get('instanceIdInput').patchValue(null, {emitEvent: true}); + this.instanceIdInput.nativeElement.value = ""; + setTimeout(() => { + this.instanceIdInput.nativeElement.blur(); + this.instanceIdInput.nativeElement.focus(); + }, 0); + } + + onkeydown(e: KeyboardEvent) { + if (e.keyCode == 189 || e.keyCode == 187 || e.keyCode == 109 || e.keyCode == 107) { + return false; + } else if (e.keyCode == 8) { + if (this.lwm2mObjectListFormGroup.get('instanceIdInput').value == null) { + this.clear(); + } + this.instanceIdInput.nativeElement.focus(); + } + } + + onFocus() { + if (this.dirty) { + this.lwm2mObjectListFormGroup.get('instanceIdInput').updateValueAndValidity({onlySelf: true, emitEvent: true}); + this.dirty = false; + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.html new file mode 100644 index 0000000000..b8d10689e1 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.html @@ -0,0 +1,54 @@ + +
+ + {{data.objectName}}    (object [{{data.objectId}}]) + + + + + +
+
+
+
+ + +
+
+
+
+ + + +
+
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.ts new file mode 100644 index 0000000000..62f516b660 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.ts @@ -0,0 +1,67 @@ +/// +/// Copyright © 2016-2020 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component, Inject, OnInit } from '@angular/core'; +import { DialogComponent } from '@shared/components/dialog.component'; +import { ControlValueAccessor, FormBuilder, FormGroup } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { Router } from '@angular/router'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { TranslateService } from '@ngx-translate/core'; + +export interface Lwm2mObjectAddInstancesData { + instancesIds: Set; + objectName?: string; + objectId?: number; +} + +@Component({ + selector: 'tb-lwm2m-object-add-instances', + templateUrl: './lwm2m-object-add-instances.component.html', + styleUrls: [] +}) +export class Lwm2mObjectAddInstancesComponent extends DialogComponent implements OnInit { + + jsonFormGroup: FormGroup; + // title: string; + + submitted = false; + + constructor(protected store: Store, + protected router: Router, + @Inject(MAT_DIALOG_DATA) public data: Lwm2mObjectAddInstancesData, + public dialogRef: MatDialogRef, + public fb: FormBuilder) { + super(store, router, dialogRef); + } + + + ngOnInit(): void { + this.jsonFormGroup = this.fb.group({ + instancesIds: this.data.instancesIds + }) + } + + cancel(): void { + this.dialogRef.close(undefined); + } + + add(): void { + this.data.instancesIds = this.jsonFormGroup.get('instancesIds').value + this.dialogRef.close(this.data); + } +} diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.html new file mode 100644 index 0000000000..7ad661752b --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.html @@ -0,0 +1,56 @@ + + + + + + {{objectLwm2m.name}} + close + + + + + + + + + + {{ translate.get('device-profile.lwm2m.no-objects-matching', {object: searchText}) | async }} + + + + + {{ 'device-profile.lwm2m.object-list-empty' | translate }} + + + diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts new file mode 100644 index 0000000000..b0f9ea4ebf --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts @@ -0,0 +1,234 @@ +/// +/// Copyright © 2016-2020 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { + Component, + forwardRef, + Input, + OnInit, + ViewChild, + ElementRef, + Output, + EventEmitter +} from "@angular/core"; +import { + ControlValueAccessor, + FormBuilder, + FormGroup, + NG_VALUE_ACCESSOR, Validators +} from "@angular/forms"; +import {coerceBooleanProperty} from "@angular/cdk/coercion"; +import {Store} from "@ngrx/store"; +import {AppState} from "../../../../../../core/core.state"; +import {MatChipList} from '@angular/material/chips'; +import {MatAutocomplete} from "@angular/material/autocomplete"; +import {Observable} from "rxjs"; +import {filter, map, mergeMap, share, tap} from 'rxjs/operators'; +import {ObjectLwM2M} from "./profile-config.models"; +import {TranslateService} from "@ngx-translate/core"; +import {DeviceProfileService} from "../../../../../../core/http/device-profile.service"; +import {PageLink} from "../../../../../../shared/models/page/page-link"; +import {Direction} from "../../../../../../shared/models/page/sort-order"; + +@Component({ + selector: 'tb-profile-lwm2m-object-list', + templateUrl: './lwm2m-object-list.component.html', + styleUrls: [], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => Lwm2mObjectListComponent), + multi: true + }] +}) +export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, Validators { + + lwm2mObjectListFormGroup: FormGroup; + private requiredValue: boolean; + modelValue: Array | null; + objectsList: Array = []; + filteredObjectsList: Observable>; + private disabled = false as boolean; + searchText = '' as string; + private dirty = false as boolean; + + get required(): boolean { + return this.requiredValue; + } + + @Input() + set required(value: boolean) { + const newVal = coerceBooleanProperty(value); + if (this.requiredValue !== newVal) { + this.requiredValue = newVal; + this.updateValidators(); + } + } + + @Output() + addList = new EventEmitter(); + + @Output() + removeList = new EventEmitter(); + + @ViewChild('objectInput') objectInput: ElementRef; + @ViewChild('objectAutocomplete') matAutocomplete: MatAutocomplete; + @ViewChild('chipList', {static: true}) chipList: MatChipList; + + private propagateChange = (v: any) => { + }; + + constructor(private store: Store, + public translate: TranslateService, + private deviceProfileService: DeviceProfileService, + private fb: FormBuilder) { + this.lwm2mObjectListFormGroup = this.fb.group({ + objectsList: [this.objectsList], + objectLwm2m: [null, this.required ? [Validators.required] : []] + }); + } + + updateValidators() { + this.lwm2mObjectListFormGroup.get('objectLwm2m').setValidators(this.required ? [Validators.required] : []); + this.lwm2mObjectListFormGroup.get('objectLwm2m').updateValueAndValidity(); + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + ngOnInit() { + this.filteredObjectsList = this.lwm2mObjectListFormGroup.get('objectLwm2m').valueChanges + .pipe( + tap((value) => { + if (value && typeof value !== 'string') { + this.add(value); + } else if (value === null) { + this.clear(this.objectInput.nativeElement.value); + } + }), + filter((value) => typeof value === 'string'), + map((value) => value ? (typeof value === 'string' ? value : value.name) : ''), + mergeMap(name => this.fetchListObjects(name)), + share() + ); + } + + ngAfterViewInit(): void { + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + if (isDisabled) { + this.lwm2mObjectListFormGroup.disable({emitEvent: false}); + } else { + this.lwm2mObjectListFormGroup.enable({emitEvent: false}); + } + } + + writeValue(value: any): void { + this.searchText = ''; + if (value.hasOwnProperty("objectIds") && value["objectIds"] != null && value["objectIds"].length > 0) { + this.modelValue = [...value["objectIds"]]; + this.objectsList = value["objectsList"]; + this.lwm2mObjectListFormGroup.get('objectsList').setValue(this.objectsList); + } else { + this.objectsList = []; + this.lwm2mObjectListFormGroup.get('objectsList').setValue(this.objectsList); + this.modelValue = null; + } + this.dirty = true; + } + + reset() { + this.objectsList = []; + this.lwm2mObjectListFormGroup.get('objectsList').setValue(this.objectsList); + this.modelValue = null; + if (this.objectInput) { + this.objectInput.nativeElement.value = ''; + } + this.lwm2mObjectListFormGroup.get('objectLwm2m').patchValue('', {emitEvent: false}); + this.propagateChange(this.modelValue); + this.dirty = true; + } + + add(object: ObjectLwM2M): void { + if (!this.modelValue || this.modelValue.indexOf(object.id) === -1) { + if (!this.modelValue) { + this.modelValue = []; + } + this.modelValue.push(object.id); + this.objectsList.push(object); + this.lwm2mObjectListFormGroup.get('objectsList').setValue(this.objectsList); + this.addList.next(this.objectsList); + } + this.propagateChange(this.modelValue); + this.clear(); + } + + remove(object: ObjectLwM2M) { + let index = this.objectsList.indexOf(object); + if (index >= 0) { + this.objectsList.splice(index, 1); + this.lwm2mObjectListFormGroup.get('objectsList').setValue(this.objectsList); + index = this.modelValue.indexOf(object.id); + this.modelValue.splice(index, 1); + this.removeList.next(object); + if (!this.modelValue.length) { + this.modelValue = null; + } + this.propagateChange(this.modelValue); + this.clear(); + } + } + + displayObjectLwm2mFn(object?: ObjectLwM2M): string | undefined { + return object ? object.name : undefined; + } + + fetchListObjects(searchText?: string): Observable> { + this.searchText = searchText; + const pageLink = new PageLink(10, 0, searchText, { + property: 'name', + direction: Direction.ASC + }); + return this.deviceProfileService.getLwm2mObjectsPage(pageLink, {ignoreLoading: true}).pipe( + map(pageData => { + let data = pageData.data; + return data; + }) + ); + } + + onFocus() { + if (this.dirty) { + this.lwm2mObjectListFormGroup.get('objectLwm2m').updateValueAndValidity({onlySelf: true, emitEvent: true}); + this.dirty = false; + } + } + + clear(value: string = '') { + this.objectInput.nativeElement.value = value; + this.lwm2mObjectListFormGroup.get('objectLwm2m').patchValue(value, {emitEvent: true}); + setTimeout(() => { + this.objectInput.nativeElement.blur(); + this.objectInput.nativeElement.focus(); + }, 0); + } +} diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resource.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resource.component.html new file mode 100644 index 0000000000..322fba8086 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resource.component.html @@ -0,0 +1,86 @@ + +
+
+
+
+
+ +
+
+ + device-profile.lwm2m.observe-label + +
+
+ + device-profile.lwm2m.attribute-label + +
+
+ + device-profile.lwm2m.telemetry-label + +
+
+ + device-profile.lwm2m.key-name-label + +
+
+
+
+ Resource[{{resourceLwM2M.get('id').value}}] + name:{{resourceLwM2M.get('name').value}} +
+
+ + +
+
+ + +
+
+ + +
+ + + {{ 'device-profile.lwm2m.key-name_label' | translate }} + + + + {{ 'device-profile.lwm2m.key-name' | translate }} + {{ 'device-profile.lwm2m.required' | translate }} + + +
+
+
+
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resource.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resource.component.ts new file mode 100644 index 0000000000..f94cd589ae --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resource.component.ts @@ -0,0 +1,156 @@ +/// +/// Copyright © 2016-2020 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component, EventEmitter, forwardRef, Input, OnInit, Output, ViewChild } from "@angular/core"; +import { + ControlValueAccessor, + FormArray, FormBuilder, + FormGroup, + NG_VALUE_ACCESSOR, Validators +} from "@angular/forms"; +import { + CAMEL_CASE_REGEXP, + ResourceLwM2M +} from '@home/components/profile/device/lwm2m/profile-config.models'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { deepClone, isUndefined } from '@core/utils'; +import { coerceBooleanProperty } from '@angular/cdk/coercion'; + +@Component({ + selector: 'tb-profile-lwm2m-observe-attr-telemetry-resource', + templateUrl: './lwm2m-observe-attr-telemetry-resource.component.html', + styleUrls: [], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => Lwm2mObserveAttrTelemetryResourceComponent), + multi: true + } + ] +}) + +export class Lwm2mObserveAttrTelemetryResourceComponent implements ControlValueAccessor, OnInit, Validators { + + resourceFormGroup : FormGroup; + + disabled = false as boolean; + private requiredValue: boolean; + + get required(): boolean { + return this.requiredValue; + } + + @Input() + set required(value: boolean) { + const newVal = coerceBooleanProperty(value); + if (this.requiredValue !== newVal) { + this.requiredValue = newVal; + } + } + constructor(private store: Store, + private fb: FormBuilder) { + this.resourceFormGroup = this.fb.group({'resources': this.fb.array([])}); + this.resourceFormGroup.valueChanges.subscribe(value => { + if (!this.disabled) { + this.propagateChangeState(value.resources); + } + }); + } + + ngOnInit(): void { + } + + registerOnTouched(fn: any): void { + } + + writeValue(value: ResourceLwM2M[]): void { + this.createResourceLwM2M(value); + } + + get resourceFormArray(): FormArray{ + return this.resourceFormGroup.get('resources') as FormArray; + } + + resourceLwm2mFormArray(instance: FormGroup): FormArray { + return instance.get('resources') as FormArray; + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + if (isDisabled) { + this.resourceFormGroup.disable(); + } else { + this.resourceFormGroup.enable(); + } + } + + getDisabledState(): boolean { + return this.disabled; + } + + updateValueKeyName (event: any, z: number): void { + this.resourceFormArray.at(z).patchValue( {keyName: this.keysToCamel(deepClone(event.target.value))} ); + } + + keysToCamel(o: any): string { + let val = o.split(" "); + let playStore = []; + val.forEach(function (item, k){ + item = item.replace(CAMEL_CASE_REGEXP, ''); + item = (k===0)? item.charAt(0).toLowerCase() + item.substr(1) : item.charAt(0).toUpperCase() + item.substr(1) + playStore.push(item); + }); + return playStore.join(''); + } + + createResourceLwM2M(resourcesLwM2MJson: ResourceLwM2M []): void { + if(resourcesLwM2MJson.length === this.resourceFormArray.length) { + this.resourceFormArray.patchValue(resourcesLwM2MJson, {emitEvent: false}) + } else { + this.resourceFormArray.clear(); + resourcesLwM2MJson.forEach(resourceLwM2M => { + this.resourceFormArray.push(this.fb.group({ + id: resourceLwM2M.id, + name: resourceLwM2M.name, + observe: resourceLwM2M.observe, + attribute: resourceLwM2M.attribute, + telemetry: resourceLwM2M.telemetry, + keyName: [resourceLwM2M.keyName, Validators.required] + })); + }) + } + } + + private propagateChange = (v: any) => { + }; + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + private propagateChangeState(value: any): void { + if (value && this.resourceFormGroup.valid) { + this.propagateChange(value); + } else { + this.propagateChange(null); + } + } + + trackByParams(index: number): number { + return index; + } +} diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.css b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.css new file mode 100644 index 0000000000..9d2aa31a2c --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.css @@ -0,0 +1,49 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +.vertical-padding { + padding: 0 0 10px 20px; +} + +.left-padding { + padding-left: 5px; +} + +.tb-panel-title-height { + user-select: none; + min-height: 32px; +} + +.checkbox-padding { + padding-left: 22px; +} + +.label-resource { + /*padding: 4px;*/ + color: #002699; + /*text-transform: uppercase;*/ + background: rgba(220, 220, 220, .35); + border-radius: 20px; + width: inherit; + /*margin: 10px 0;*/ + overflow: hidden; + font-size: 15px; + text-overflow: ellipsis; + white-space: nowrap; + opacity: .8; + text-align:center; +} + diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.html new file mode 100644 index 0000000000..ea3233f769 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.html @@ -0,0 +1,102 @@ + + +
+ + + + +
{{ objectLwM2M.get('name').value}} (object [{{ objectLwM2M.get('id').value}}])
+ +
+
+
+ + + + +
+
+
+ Instance [{{instances.get('id').value}}] +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+
+
+
+ + + + +
+
+
+
+
+
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts new file mode 100644 index 0000000000..8482fde97a --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts @@ -0,0 +1,352 @@ +/// +/// Copyright © 2016-2020 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + + +import { Component, forwardRef, Input, OnInit, Output } from "@angular/core"; +import { + AbstractControl, + ControlValueAccessor, + FormArray, + FormBuilder, + FormGroup, + NG_VALUE_ACCESSOR, + Validators +} from "@angular/forms"; +import { Store } from "@ngrx/store"; +import { AppState } from "@core/core.state"; +import { coerceBooleanProperty } from "@angular/cdk/coercion"; +import { + ATTR, + Instance, + ObjectLwM2M, + OBSERVE, + ResourceLwM2M, + TELEMETRY +} from "./profile-config.models"; +import { isNotNullOrUndefined } from 'codelyzer/util/isNotNullOrUndefined'; +import { deepClone, isUndefined } from '@core/utils'; +import { MatDialog } from '@angular/material/dialog'; +import { TranslateService } from '@ngx-translate/core'; +import { + Lwm2mObjectAddInstancesComponent, + Lwm2mObjectAddInstancesData +} from '@home/components/profile/device/lwm2m/lwm2m-object-add-instances.component'; +import { Control } from 'leaflet'; + +@Component({ + selector: 'tb-profile-lwm2m-observe-attr-telemetry', + templateUrl: './lwm2m-observe-attr-telemetry.component.html', + styleUrls: ['./lwm2m-observe-attr-telemetry.component.css'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => Lwm2mObserveAttrTelemetryComponent), + multi: true + } + ] +}) + +export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor, OnInit, Validators { + + valuePrev = null as any; + observeAttrTelemetryFormGroup: FormGroup; + observe = OBSERVE as string; + attribute = ATTR as string; + telemetry = TELEMETRY as string; + private requiredValue: boolean; + + get required(): boolean { + return this.requiredValue; + } + + @Input() + disabled: boolean; + + @Input() + set required(value: boolean) { + const newVal = coerceBooleanProperty(value); + if (this.requiredValue !== newVal) { + this.requiredValue = newVal; + this.updateValidators(); + } + } + + constructor(private store: Store, + private fb: FormBuilder, + private dialog: MatDialog, + private translate: TranslateService) { + this.observeAttrTelemetryFormGroup = this.fb.group({ + clientLwM2M: this.fb.array([]) + }); + this.observeAttrTelemetryFormGroup.valueChanges.subscribe(value => { + if (isUndefined(this.disabled) || !this.disabled) { + this.propagateChangeState(value); + } + }); + } + + ngOnInit(): void { + } + + private propagateChange = (v: any) => { + }; + + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + private propagateChangeState(value: any): void { + if (value) { + if (this.valuePrev === null) { + this.valuePrev = "init"; + } else if (this.valuePrev === "init") { + this.valuePrev = value; + } else if (JSON.stringify(value) !== JSON.stringify(this.valuePrev)) { + this.valuePrev = value; + if (this.observeAttrTelemetryFormGroup.valid) { + this.propagateChange(value); + } else { + this.propagateChange(null); + } + } + } + } + + registerOnTouched(fn: any): void { + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + this.valuePrev = null; + if (isDisabled) { + this.observeAttrTelemetryFormGroup.disable(); + } else { + this.observeAttrTelemetryFormGroup.enable(); + } + } + + getDisabledState(): boolean { + return this.disabled; + } + + writeValue(value: any): void { + this.buildClientObjectsLwM2M(value.clientLwM2M); + } + + private buildClientObjectsLwM2M(objectsLwM2M: ObjectLwM2M []): void { + this.observeAttrTelemetryFormGroup.setControl('clientLwM2M', + this.createObjectsLwM2M(objectsLwM2M) + ); + } + + createObjectsLwM2M(objectsLwM2MJson: ObjectLwM2M []): FormArray { + return this.fb.array(objectsLwM2MJson.map((objectLwM2M) => { + return this.fb.group({ + id: objectLwM2M.id, + name: objectLwM2M.name, + multiple: objectLwM2M.multiple, + mandatory: objectLwM2M.mandatory, + instances: this.createInstanceLwM2M(objectLwM2M.instances) + }) + })) + } + + createInstanceLwM2M(instanceLwM2MJson: Instance []): FormArray { + return this.fb.array(instanceLwM2MJson.map((instanceLwM2M, index) => { + return this.fb.group({ + id: instanceLwM2M.id, + [this.observe]: {value: false, disabled: this.disabled}, + [this.attribute]: {value: false, disabled: this.disabled}, + [this.telemetry]: {value: false, disabled: this.disabled}, + resources: {value: instanceLwM2M.resources, disabled: this.disabled} + }) + })) + } + + clientLwM2MFormArray(formGroup: FormGroup): FormArray { + return formGroup.get('clientLwM2M') as FormArray; + } + + instancesLwm2mFormArray(objectLwM2M: AbstractControl): FormArray { + return objectLwM2M.get('instances') as FormArray; + } + + changeInstanceResourcesCheckBox(value: boolean, instance: AbstractControl, type: string): void { + let resources = instance.get('resources').value as ResourceLwM2M [] + resources.forEach(resource => resource[type] = value); + instance.get('resources').patchValue(resources); + this.propagateChange(this.observeAttrTelemetryFormGroup.value); + } + + updateValidators() { + this.observeAttrTelemetryFormGroup.get('clientLwM2M').setValidators(this.required ? [Validators.required] : []); + this.observeAttrTelemetryFormGroup.get('clientLwM2M').updateValueAndValidity(); + } + + trackByParams(index: number): number { + return index; + } + + getIndeterminate(instance: AbstractControl, type: string) { + const resources = instance.get('resources').value as ResourceLwM2M []; + if (isNotNullOrUndefined(resources)) { + const isType = (element) => element[type] === true; + let checkedResource = resources.filter(isType); + if (checkedResource.length === 0) return false; + else if (checkedResource.length === resources.length) { + instance.patchValue({[type]: true}); + return false; + } else return true; + } + return false; + } + + + getChecked(instance: AbstractControl, type: string) { + const resources = instance.get('resources').value as ResourceLwM2M []; + if (isNotNullOrUndefined(resources)) { + return resources.some(resource => resource[type]); + } + return false; + } + + getExpended(objectLwM2M: AbstractControl) { + return this.instancesLwm2mFormArray(objectLwM2M).length === 1; + } + + /** + * Instances: indicates whether this Object supports multiple Object Instances or not. + * 1) Field in object: == Multiple/Single + * 2) Field in object: == Mandatory/Optional + * If this field is “Multiple” then the number of Object Instance can be from 0 to many (Object Instance ID MAX_ID=65535). + * If this field is “Single” then the number of Object Instance can be from 0 to 1. (max count == 1) + * If the Object field “Mandatory” is “Mandatory” and the Object field “Instances” is “Single” then, the number of Object Instance MUST be 1. + * 1. == Multiple (true), == Optional (false) => Object Instance ID MIN_ID=0 MAX_ID=65535 (может ни одного не быть) + * 2. == Multiple (true), == Mandatory (true) => Object Instance ID MIN_ID=0 MAX_ID=65535 (min один обязательный) + * 3. == Single (false), == Optional (false) => Object Instance ID cnt_max = 1 cnt_min = 0 (может ни одного не быть) + * 4. == Single (false), == Mandatory (true) => Object Instance ID cnt_max = cnt_min = 1 (всегда есть один) + * @param $event + * @param objectId + * @param objectName + */ + + addInstances($event: Event, object: ObjectLwM2M): void { + if ($event) { + $event.stopPropagation(); + $event.preventDefault(); + } + let instancesIds = new Set(); + object.instances.forEach(inst => { + instancesIds.add(inst.id); + }); + this.dialog.open(Lwm2mObjectAddInstancesComponent, { + disableClose: true, + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], + data: { + instancesIds: this.setInstancesIds(object.instances), + objectName: object.name, + objectId: object.id + } + }).afterClosed().subscribe( + (res: Lwm2mObjectAddInstancesData | undefined) => { + if (isNotNullOrUndefined(res)) { + this.updateInstancesIds(res); + } + } + ); + } + + updateInstancesIds(data: Lwm2mObjectAddInstancesData) { + let valueNew = new Set(); + let valueOld = new Set(); + data.instancesIds.forEach(value => { + valueNew.add(value); + }) + let oldInstances = (this.observeAttrTelemetryFormGroup.get('clientLwM2M').value as ObjectLwM2M []).find(e => e.id == data.objectId).instances; + oldInstances.forEach(inst => { + valueOld.add(inst.id); + }); + if (JSON.stringify(Array.from(valueOld)) != JSON.stringify(Array.from(valueNew))) { + let idsDel = this.diffBetweenSet(valueNew, this.deepCloneSet(valueOld)); + let idsAdd = this.diffBetweenSet(valueOld, this.deepCloneSet(valueNew)); + if (idsAdd.size) { + this.addInstancesNew(data.objectId, idsAdd) + } + if (idsDel.size) { + this.delInstances(data.objectId, idsDel); + } + } + } + + delInstances(objectId: number, idsDel: Set): void { + let isIdIndex = (element) => element.id == objectId; + let objectIndex = (this.observeAttrTelemetryFormGroup.get('clientLwM2M').value as ObjectLwM2M []).findIndex(isIdIndex); + idsDel.forEach(x => { + isIdIndex = (element) => element.value.id == x; + let instancesFormArray = ((this.observeAttrTelemetryFormGroup.get('clientLwM2M') as FormArray).controls[objectIndex].get("instances") as FormArray); + let instanceIndex = instancesFormArray.controls.findIndex(isIdIndex); + instancesFormArray.removeAt(instanceIndex); + }) + } + + addInstancesNew(objectId: number, idsAdd: Set): void { + let instancesValue = (this.observeAttrTelemetryFormGroup.get('clientLwM2M').value as ObjectLwM2M []).find(e => e.id == objectId).instances; + let instancesFormArray = ((this.observeAttrTelemetryFormGroup.get('clientLwM2M') as FormArray).controls.find(e => e.value.id == objectId).get("instances") as FormArray) as FormArray; + idsAdd.forEach(x => { + let instanceNew = deepClone(instancesValue[0]) as Instance; + instanceNew.id = x; + instanceNew.resources.forEach(r => { + r.attribute = false; + r.telemetry = false; + r.observe = false; + }); + instancesFormArray.push(this.fb.group({ + id: x, + [this.observe]: {value: false, disabled: this.disabled}, + [this.attribute]: {value: false, disabled: this.disabled}, + [this.telemetry]: {value: false, disabled: this.disabled}, + resources: {value: instanceNew.resources, disabled: this.disabled} + })); + }); + (instancesFormArray.controls as FormGroup[]).sort((a,b) => a.value.id - b.value.id); + } + + deepCloneSet(oldSet: Set): Set { + let newSet = new Set(); + oldSet.forEach(p => { + newSet.add(p); + }) + return newSet; + } + + diffBetweenSet(firstSet: Set, secondSet: Set): Set { + firstSet.forEach(p => { + secondSet.delete(p); + }) + return secondSet + } + + setInstancesIds(instances: Instance []): Set { + let instancesIds = new Set(); + if (instances && instances.length) { + instances.forEach(inst => { + instancesIds.add(inst.id); + }); + } + return instancesIds; + } +} diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-components.module.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-components.module.ts new file mode 100644 index 0000000000..1f829aee19 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-components.module.ts @@ -0,0 +1,55 @@ +/// +/// Copyright © 2016-2020 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { NgModule } from '@angular/core'; +import { Lwm2mDeviceProfileTransportConfigurationComponent } from './lwm2m-device-profile-transport-configuration.component'; +import { Lwm2mObjectListComponent } from './lwm2m-object-list.component'; +import { Lwm2mObserveAttrTelemetryComponent } from './lwm2m-observe-attr-telemetry.component'; +import { Lwm2mObserveAttrTelemetryResourceComponent } from './lwm2m-observe-attr-telemetry-resource.component'; +import { Lwm2mDeviceConfigServerComponent } from './lwm2m-device-config-server.component'; +import { Lwm2mObjectAddInstancesComponent } from './lwm2m-object-add-instances.component'; +import { Lwm2mObjectAddInstancesListComponent } from './lwm2m-object-add-instances-list.component'; +import { CommonModule } from '@angular/common'; +import { SharedModule } from '@app/shared/shared.module'; + +@NgModule({ + declarations: + [ + Lwm2mDeviceProfileTransportConfigurationComponent, + Lwm2mObjectListComponent, + Lwm2mObserveAttrTelemetryComponent, + Lwm2mObserveAttrTelemetryResourceComponent, + Lwm2mDeviceConfigServerComponent, + Lwm2mObjectAddInstancesComponent, + Lwm2mObjectAddInstancesListComponent + ], + imports: [ + CommonModule, + SharedModule + ], + exports: [ + Lwm2mDeviceProfileTransportConfigurationComponent, + Lwm2mObjectListComponent, + Lwm2mObserveAttrTelemetryComponent, + Lwm2mObserveAttrTelemetryResourceComponent, + Lwm2mDeviceConfigServerComponent, + Lwm2mObjectAddInstancesComponent, + Lwm2mObjectAddInstancesListComponent + ], + providers: [ + ] +}) +export class Lwm2mProfileComponentsModule { } diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/profile-config.models.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/profile-config.models.ts new file mode 100644 index 0000000000..c626138828 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/profile-config.models.ts @@ -0,0 +1,212 @@ +/// +/// Copyright © 2016-2020 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { AbstractControl, ValidationErrors } from '@angular/forms'; + +export const OBSERVE_ATTR = 'observeAttr'; +export const OBSERVE = 'observe'; +export const ATTR = 'attribute'; +export const TELEMETRY = 'telemetry'; +export const KEY_NAME = 'keyName'; +export const DEFAULT_ID_SERVER = 123; +export const DEFAULT_ID_BOOTSTRAP = 111; +export const DEFAULT_HOST_NAME = "localhost"; +export const DEFAULT_PORT_SERVER_NO_SEC = 5685; +export const DEFAULT_PORT_SERVER_SEC = 5686; +export const DEFAULT_PORT_SERVER_SEC_CERT = 5688; +export const DEFAULT_PORT_BOOTSTRAP_NO_SEC = 5689; +export const DEFAULT_PORT_BOOTSTRAP_SEC = 5690; +export const DEFAULT_PORT_BOOTSTRAP_SEC_CERT = 5692; +export const DEFAULT_CLIENT_HOLD_OFF_TIME = 1; +export const DEFAULT_LIFE_TIME = 300; +export const DEFAULT_DEFAULT_MIN_PERIOD = 1; +export const DEFAULT_NOTIF_IF_DESIBLED = true; +export const DEFAULT_BINDING = "U"; +export const DEFAULT_BOOTSTRAP_SERVER_ACCOUNT_TIME_OUT = 0; +export const LEN_MAX_PUBLIC_KEY_PSK = 182; +export const LEN_MAX_PUBLIC_KEY_RPK_X509 = 3000; +export const KEY_IDENT_REGEXP_PSK = /^[0-9a-fA-F]{64,64}$/; +export const KEY_PRIVATE_REGEXP = /^[0-9a-fA-F]{134,134}$/; +export const KEY_PUBLIC_REGEXP_PSK = /^[0-9a-fA-F]{182,182}$/; +export const KEY_PUBLIC_REGEXP_X509 = /^[0-9a-fA-F]{0,3000}$/; +export const CAMEL_CASE_REGEXP = /[-_&@.,*+!?^${}()|[\]\\]/g; +export const INSTANCES_ID_VALUE_MIN = 0; +export const INSTANCES_ID_VALUE_MAX = 65535; + +//ok +export enum SECURITY_CONFIG_MODE { + PSK = 'PSK', + RPK = 'RPK', + X509 = 'X509', + NO_SEC = 'NO_SEC' +} +//ok +export const SECURITY_CONFIG_MODE_NAMES = new Map( + [ + [SECURITY_CONFIG_MODE.PSK, 'Pre-Shared Key'], + [SECURITY_CONFIG_MODE.RPK, 'Raw Public Key'], + [SECURITY_CONFIG_MODE.X509, 'X.509 Certificate'], + [SECURITY_CONFIG_MODE.NO_SEC, 'No Security'], + ] +); +//ok +export interface BootstrapServersSecurityConfig { + shortId: number, + lifetime: number, + defaultMinPeriod: number, + notifIfDisabled: boolean, + binding: string +} + +//ok +export interface ServerSecurityConfig { + host?: string, + port?: number, + bootstrapServerIs?: boolean, + securityMode: string, + clientPublicKeyOrId?: string, + clientSecretKey?: string, + serverPublicKey?: string; + clientHoldOffTime?: number, + serverId?: number, + bootstrapServerAccountTimeout: number +} + +//ok +interface BootstrapSecurityConfig { + servers: BootstrapServersSecurityConfig, + bootstrapServer: ServerSecurityConfig, + lwm2mServer: ServerSecurityConfig +} + +//ok +export interface ProfileConfigModels { + bootstrap: BootstrapSecurityConfig, + observeAttr: { + observe: string [], + attribute: string [], + telemetry: string [], + keyName: [] + } +} + +//ok +export function getDefaultBootstrapServersSecurityConfig(): BootstrapServersSecurityConfig { + return { + shortId: DEFAULT_ID_SERVER, + lifetime: DEFAULT_LIFE_TIME, + defaultMinPeriod: DEFAULT_DEFAULT_MIN_PERIOD, + notifIfDisabled: DEFAULT_NOTIF_IF_DESIBLED, + binding: DEFAULT_BINDING + } +} + +//ok +export function getDefaultBootstrapServerSecurityConfig(hostname: any): ServerSecurityConfig { + return { + host: hostname, + port: getDefaultPortBootstrap(), + bootstrapServerIs: true, + securityMode: SECURITY_CONFIG_MODE.NO_SEC.toString(), + serverPublicKey: '', + clientHoldOffTime: DEFAULT_CLIENT_HOLD_OFF_TIME, + serverId: DEFAULT_ID_BOOTSTRAP, + bootstrapServerAccountTimeout: DEFAULT_BOOTSTRAP_SERVER_ACCOUNT_TIME_OUT + } +} +//ok +export function getDefaultLwM2MServerSecurityConfig(hostname): ServerSecurityConfig { + const DefaultLwM2MServerSecurityConfig = getDefaultBootstrapServerSecurityConfig(hostname); + DefaultLwM2MServerSecurityConfig.bootstrapServerIs = false; + DefaultLwM2MServerSecurityConfig.port = getDefaultPortServer(); + DefaultLwM2MServerSecurityConfig.serverId = DEFAULT_ID_SERVER; + return DefaultLwM2MServerSecurityConfig; +} +//ok +export function getDefaultPortBootstrap(securityMode?: string): number { + return (!securityMode || securityMode === SECURITY_CONFIG_MODE.NO_SEC.toString()) ? DEFAULT_PORT_BOOTSTRAP_NO_SEC : + (securityMode === SECURITY_CONFIG_MODE.X509.toString()) ? DEFAULT_PORT_BOOTSTRAP_SEC_CERT : DEFAULT_PORT_BOOTSTRAP_SEC; +} +//ok +export function getDefaultPortServer(securityMode?: string): number { + return (!securityMode || securityMode === SECURITY_CONFIG_MODE.NO_SEC.toString()) ? DEFAULT_PORT_SERVER_NO_SEC : + (securityMode === SECURITY_CONFIG_MODE.X509.toString()) ? DEFAULT_PORT_SERVER_SEC_CERT : DEFAULT_PORT_SERVER_SEC; +} + +//ok +function getDefaultProfileBootstrapSecurityConfig(hostname: any): BootstrapSecurityConfig { + return { + servers: getDefaultBootstrapServersSecurityConfig(), + bootstrapServer: getDefaultBootstrapServerSecurityConfig(hostname), + lwm2mServer: getDefaultLwM2MServerSecurityConfig(hostname) + } +} + +//ok +export function getDefaultProfileConfig(hostname?: any): ProfileConfigModels { + return { + bootstrap: getDefaultProfileBootstrapSecurityConfig((hostname)? hostname : DEFAULT_HOST_NAME), + observeAttr: { + observe: [], + attribute: [], + telemetry: [], + keyName: [] + } + }; +} + +//ok +export interface ResourceLwM2M { + id: number, + name: string, + observe: boolean, + attribute: boolean, + telemetry: boolean, + keyName: string +} +//ok +export interface Instance { + id: number, + resources: ResourceLwM2M[] +} + +/** + * multiple == true => Multiple + * multiple == false => Single + * mandatory == true => Mandatory + * mandatory == false => Optional + */ +export interface ObjectLwM2M { + id: number, + name: string, + multiple?: boolean, + mandatory?: boolean, + instances?: Instance [] +} + +export function getChangeInstancesIds (): ChangeInstancesIds { + let changeInstancesIds: ChangeInstancesIds; + changeInstancesIds.add = new Set(); + changeInstancesIds.del = new Set(); + return changeInstancesIds; + +} + +export interface ChangeInstancesIds { + add: Set, + del: Set +} + diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-form.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-form.component.html index 8340857d8d..19f6b87471 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-form.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-form.component.html @@ -35,7 +35,7 @@ required > -
+
profile-tab {{'gateway.security-type' | translate }} diff --git a/ui-ngx/src/app/modules/home/pages/device/device.module.ts b/ui-ngx/src/app/modules/home/pages/device/device.module.ts index 53ee34d570..54c02f447b 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device.module.ts +++ b/ui-ngx/src/app/modules/home/pages/device/device.module.ts @@ -24,6 +24,9 @@ import { DeviceCredentialsDialogComponent } from '@modules/home/pages/device/dev import { HomeDialogsModule } from '../../dialogs/home-dialogs.module'; import { HomeComponentsModule } from '@modules/home/components/home-components.module'; import { DeviceTabsComponent } from '@home/pages/device/device-tabs.component'; +import { SecurityConfigComponent } from '@home/pages/device/lwm2m/security-config.component'; +// TODO: @nickAS21 move to device profile +import {SecurityConfigServerComponent} from "@home/pages/device/lwm2m/security-config-server.component"; import { DefaultDeviceConfigurationComponent } from './data/default-device-configuration.component'; import { DeviceConfigurationComponent } from './data/device-configuration.component'; import { DeviceDataComponent } from './data/device-data.component'; @@ -44,7 +47,9 @@ import { Lwm2mDeviceTransportConfigurationComponent } from './data/lwm2m-device- DeviceComponent, DeviceTabsComponent, DeviceTableHeaderComponent, - DeviceCredentialsDialogComponent + DeviceCredentialsDialogComponent, + SecurityConfigComponent, + SecurityConfigServerComponent ], imports: [ CommonModule, diff --git a/ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config-server.component.html b/ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config-server.component.html new file mode 100644 index 0000000000..a2be8e6334 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config-server.component.html @@ -0,0 +1,80 @@ + +
+
+
+
+ + device.lwm2m-security-config.mode + + + {{ credentialTypeLwM2MNamesMap.get(securityConfigLwM2MType[securityMode]) }} + + + +
+
+
+
+ + {{ 'device.lwm2m-security-config.client-publicKey-or-id' | translate }} + + {{clientPublicKeyOrId.value?.length || 0}}/{{lenMaxClientPublicKeyOrId}} + + {{ 'device.lwm2m-security-config.client-publicKey-or-id' | translate }} + {{ 'device.lwm2m-security-config.required' | translate }} + + + {{ 'device.lwm2m-security-config.client-key' | translate }} + {{ 'device.lwm2m-security-config.pattern_hex_dec_182' | translate }} + + + {{ 'device.lwm2m-security-config.client-key' | translate }} + {{ 'device.lwm2m-security-config.pattern_hex_dec' | translate }} + + + + {{ 'device.lwm2m-security-config.client-secret-key' | translate }} + + {{clientSecretKey.value?.length || 0}}/{{lenMaxClientSecretKey}} + + {{ 'device.lwm2m-security-config.client-secret-key' | translate }} + {{ 'device.lwm2m-security-config.required' | translate }} + + + {{ 'device.lwm2m-security-config.client-key' | translate }} + {{ 'device.lwm2m-security-config.pattern_hex_dec_134' | translate }} + + + {{ 'device.lwm2m-security-config.client-key' | translate }} + {{ 'device-profile.lwm2m.pattern_hex_dec_64' | translate }} + + +
+
+
+
diff --git a/ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config-server.component.ts b/ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config-server.component.ts new file mode 100644 index 0000000000..d60ff447c6 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config-server.component.ts @@ -0,0 +1,128 @@ +/// +/// Copyright © 2016-2020 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import {Component, forwardRef, Inject, Input, OnInit, ViewChild} from "@angular/core"; + +import { + ControlValueAccessor, + FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators +} from "@angular/forms"; +import { + SECURITY_CONFIG_MODE, + SECURITY_CONFIG_MODE_NAMES, + KEY_IDENT_REGEXP_PSK, + ServerSecurityConfig, + DeviceCredentialsDialogLwm2mData, + LEN_MAX_PSK, + LEN_MAX_PRIVATE_KEY, LEN_MAX_PUBLIC_KEY_RPK, KEY_PRIVATE_REGEXP, LEN_MAX_PUBLIC_KEY_X509, KEY_PUBLIC_REGEXP_X509 +} from "@home/pages/device/lwm2m/security-config.models"; +import {Store} from "@ngrx/store"; +import {AppState} from "@core/core.state"; +import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; +import {PageComponent} from "@shared/components/page.component"; +import {MatPaginator} from "@angular/material/paginator"; +import { TranslateService } from '@ngx-translate/core'; + +@Component({ + selector: 'tb-security-config-server-lwm2m', + templateUrl: './security-config-server.component.html', + styleUrls: [], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => SecurityConfigServerComponent), + multi: true + } + ] +}) + +export class SecurityConfigServerComponent extends PageComponent implements OnInit, ControlValueAccessor { + + securityConfigLwM2MType = SECURITY_CONFIG_MODE; + securityConfigLwM2MTypes = Object.keys(SECURITY_CONFIG_MODE); + credentialTypeLwM2MNamesMap = SECURITY_CONFIG_MODE_NAMES; + lenMaxClientPublicKeyOrId = LEN_MAX_PSK; + lenMaxClientSecretKey = LEN_MAX_PRIVATE_KEY; + + @Input() serverFormGroup: FormGroup; + + @ViewChild(MatPaginator) paginator: MatPaginator; + + constructor(protected store: Store, + @Inject(MAT_DIALOG_DATA) public data: DeviceCredentialsDialogLwm2mData, + public dialogRef: MatDialogRef, + public translate: TranslateService, + public fb: FormBuilder) { + super(store); + } + + ngOnInit(): void { + this.registerDisableOnLoadFormControl(this.serverFormGroup.get('securityMode')); + } + + updateValueFields(serverData: ServerSecurityConfig): void { + this.serverFormGroup.patchValue(serverData, {emitEvent: false}); + const securityMode = this.serverFormGroup.get('securityMode').value as SECURITY_CONFIG_MODE; + this.updateValidate(securityMode); + } + + updateValidate(securityMode: SECURITY_CONFIG_MODE): void { + switch (securityMode) { + case SECURITY_CONFIG_MODE.NO_SEC: + this.serverFormGroup.get('clientPublicKeyOrId').setValidators([]); + this.serverFormGroup.get('clientSecretKey').setValidators([]); + break; + case SECURITY_CONFIG_MODE.PSK: + this.lenMaxClientPublicKeyOrId = LEN_MAX_PUBLIC_KEY_RPK; + this.lenMaxClientSecretKey = LEN_MAX_PSK; + this.serverFormGroup.get('clientPublicKeyOrId').setValidators([Validators.required]); + this.serverFormGroup.get('clientSecretKey').setValidators([Validators.required, Validators.pattern(KEY_IDENT_REGEXP_PSK)]); + break; + case SECURITY_CONFIG_MODE.RPK: + this.lenMaxClientPublicKeyOrId = LEN_MAX_PUBLIC_KEY_X509; + this.lenMaxClientSecretKey = LEN_MAX_PRIVATE_KEY; + this.serverFormGroup.get('clientPublicKeyOrId').setValidators([Validators.required, Validators.pattern(KEY_PUBLIC_REGEXP_X509)]); + this.serverFormGroup.get('clientSecretKey').setValidators([Validators.required, Validators.pattern(KEY_PRIVATE_REGEXP)]); + break; + case SECURITY_CONFIG_MODE.X509: + this.lenMaxClientPublicKeyOrId = LEN_MAX_PUBLIC_KEY_X509; + this.lenMaxClientSecretKey = LEN_MAX_PRIVATE_KEY; + this.serverFormGroup.get('clientPublicKeyOrId').setValidators([Validators.required, Validators.pattern(KEY_PUBLIC_REGEXP_X509)]); + this.serverFormGroup.get('clientSecretKey').setValidators([Validators.required, Validators.pattern(KEY_PRIVATE_REGEXP)]); + break; + } + this.serverFormGroup.updateValueAndValidity(); + } + + securityModeChanged(securityMode: SECURITY_CONFIG_MODE): void { + this.updateValidate(securityMode); + } + + writeValue(value: any): void { + if (value) { + this.updateValueFields(value); + } + } + + registerOnChange(fn: (value: any) => any): void { + } + + registerOnTouched(fn: any): void { + } + + setDisabledState?(isDisabled: boolean): void { + } +} diff --git a/ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config.component.html b/ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config.component.html new file mode 100644 index 0000000000..20b163503c --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config.component.html @@ -0,0 +1,160 @@ + +
+ +

{{ title }}

+ + +
+
+
+ + device.lwm2m-security-config.endpoint + + + {{ 'device.lwm2m-security-config.endpoint' | translate }} + {{ 'device.lwm2m-security-config.required' | translate }} + + + + +
+ + device.lwm2m-security-config.mode + + + {{ credentialTypeLwM2MNamesMap.get(securityConfigLwM2MType[securityConfigClientMode]) }} + + + +
+ + {{ 'device.lwm2m-security-config.identity' | translate }} + + + {{ 'device.lwm2m-security-config.identity' | translate }} + {{ 'device.lwm2m-security-config.required' | translate }} + + +
+
+ + {{ 'device.lwm2m-security-config.client-key' | translate }} + + {{clientKey.value?.length || 0}}/{{lenMaxKeyClient}} + + {{ 'device.lwm2m-security-config.client-key' | translate }} + {{ 'device.lwm2m-security-config.required' | translate }} + + + {{ 'device.lwm2m-security-config.client-key' | translate }} + {{ 'device-profile.lwm2m-security-config.pattern_hex_dec_64' | translate }} + + + {{ 'device.lwm2m-security-config.client-key' | translate }} + {{ 'device.lwm2m-security-config.pattern_hex_dec_182' | translate }} + + +
+
+ + {{ 'device.lwm2m-security-config.client-certificate' | translate }} + +
+
+
+ +
+ + + + +
{{ 'device.lwm2m-security-config.bootstrap-server' | translate | uppercase }}
+
+
+
+ + +
+
+
+ + + + +
{{ 'device.lwm2m-security-config.lwm2m-server' | translate | uppercase }}
+
+
+
+ + +
+
+
+
+
+ +
+
+ + +
+
+
+
+
+
+
+ + + +
+
diff --git a/ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config.component.ts b/ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config.component.ts new file mode 100644 index 0000000000..a43f21431a --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config.component.ts @@ -0,0 +1,384 @@ +/// +/// Copyright © 2016-2020 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + + +import {Component, Inject, OnInit} from '@angular/core'; +import {DialogComponent} from '@shared/components/dialog.component'; +import {Store} from '@ngrx/store'; +import {AppState} from '@core/core.state'; +import {Router} from '@angular/router'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; +import {FormBuilder, FormGroup, Validators} from '@angular/forms'; +import {TranslateService} from '@ngx-translate/core'; +import { + SECURITY_CONFIG_MODE_NAMES, + SECURITY_CONFIG_MODE, + SecurityConfigModels, + ClientSecurityConfigPSK, + ClientSecurityConfigRPK, + JSON_ALL_CONFIG, + KEY_IDENT_REGEXP_PSK, + KEY_PUBLIC_REGEXP_PSK, + DeviceCredentialsDialogLwm2mData, + BOOTSTRAP_SERVER, + BOOTSTRAP_SERVERS, + LWM2M_SERVER, + ClientSecurityConfigX509, + ClientSecurityConfigNO_SEC, + getDefaultClientSecurityConfigType, + LEN_MAX_PSK, + LEN_MAX_PUBLIC_KEY_RPK +} from "./security-config.models"; +import {WINDOW} from "@core/services/window.service"; +import {MatTabChangeEvent, MatTabGroup} from "@angular/material/tabs"; +import {MatTab} from "@angular/material/tabs/tab"; + + +@Component({ + selector: 'tb-security-config-lwm2m', + templateUrl: './security-config.component.html', + styleUrls: [] +}) + +export class SecurityConfigComponent extends DialogComponent implements OnInit { + + lwm2mConfigFormGroup: FormGroup; + title: string; + submitted = false; + securityConfigLwM2MType = SECURITY_CONFIG_MODE; + securityConfigLwM2MTypes = Object.keys(SECURITY_CONFIG_MODE); + credentialTypeLwM2MNamesMap = SECURITY_CONFIG_MODE_NAMES; + formControlNameJsonAllConfig = JSON_ALL_CONFIG; + jsonAllConfig: SecurityConfigModels; + bootstrapServers: string; + bootstrapServer: string; + lwm2mServer: string; + jsonObserveData: {}; + lenMaxKeyClient = LEN_MAX_PSK; + tabPrevious: MatTab + tabIndexPrevious = 0 as number; + + constructor(protected store: Store, + protected router: Router, + @Inject(MAT_DIALOG_DATA) public data: DeviceCredentialsDialogLwm2mData, + public dialogRef: MatDialogRef, + public fb: FormBuilder, + private translate: TranslateService, + @Inject(WINDOW) private window: Window) { + super(store, router, dialogRef); + } + + ngOnInit(): void { + this.jsonAllConfig = JSON.parse(JSON.stringify(this.data.jsonAllConfig)) as SecurityConfigModels; + this.initConstants(); + this.lwm2mConfigFormGroup = this.initLwm2mConfigFormGroup(); + this.title = this.translate.instant('device.lwm2m-security-info') + ": " + this.data.endPoint + this.lwm2mConfigFormGroup.get('clientCertificate').disable(); + this.initClientSecurityConfig(this.lwm2mConfigFormGroup.get('jsonAllConfig').value); + this.registerDisableOnLoadFormControl(this.lwm2mConfigFormGroup.get('securityConfigClientMode')); + } + + initConstants(): void { + this.bootstrapServers = BOOTSTRAP_SERVERS; + this.bootstrapServer = BOOTSTRAP_SERVER; + this.lwm2mServer = LWM2M_SERVER; + } + + /** + * initChildesFormGroup + */ + get bootstrapFormGroup(): FormGroup { + return this.lwm2mConfigFormGroup.get('bootstrapFormGroup') as FormGroup; + } + + get lwm2mServerFormGroup(): FormGroup { + return this.lwm2mConfigFormGroup.get('lwm2mServerFormGroup') as FormGroup; + } + + get observeAttrFormGroup(): FormGroup { + return this.lwm2mConfigFormGroup.get('observeFormGroup') as FormGroup; + } + + initClientSecurityConfig(jsonAllConfig: SecurityConfigModels): void { + switch (jsonAllConfig.client.securityConfigClientMode.toString()) { + case SECURITY_CONFIG_MODE.NO_SEC.toString(): + break; + case SECURITY_CONFIG_MODE.PSK.toString(): + const clientSecurityConfigPSK = jsonAllConfig.client as ClientSecurityConfigPSK; + this.lwm2mConfigFormGroup.patchValue({ + identityPSK: clientSecurityConfigPSK.identity, + clientKey: clientSecurityConfigPSK.key, + }, {emitEvent: false}); + break; + case SECURITY_CONFIG_MODE.RPK.toString(): + const clientSecurityConfigRPK = jsonAllConfig.client as ClientSecurityConfigRPK; + this.lwm2mConfigFormGroup.patchValue({ + clientKey: clientSecurityConfigRPK.key, + }, {emitEvent: false}); + break; + case SECURITY_CONFIG_MODE.X509.toString(): + const clientSecurityConfigX509 = jsonAllConfig.client as ClientSecurityConfigX509; + this.lwm2mConfigFormGroup.patchValue({ + clientCertificate: clientSecurityConfigX509.x509 + }, {emitEvent: false}); + break; + } + this.securityConfigClientUpdateValidators(this.lwm2mConfigFormGroup.get('securityConfigClientMode').value); + } + + securityConfigClientModeChanged(mode: SECURITY_CONFIG_MODE): void { + switch (mode) { + case SECURITY_CONFIG_MODE.NO_SEC: + let clientSecurityConfigNO_SEC = getDefaultClientSecurityConfigType(mode) as ClientSecurityConfigNO_SEC; + this.jsonAllConfig.client = clientSecurityConfigNO_SEC; + this.lwm2mConfigFormGroup.patchValue({ + jsonAllConfig: this.jsonAllConfig, + clientCertificate: false + }, {emitEvent: true}); + break; + case SECURITY_CONFIG_MODE.PSK: + let clientSecurityConfigPSK = getDefaultClientSecurityConfigType(mode, this.lwm2mConfigFormGroup.get('endPoint').value) as ClientSecurityConfigPSK; + clientSecurityConfigPSK.identity = this.data.endPoint; + clientSecurityConfigPSK.key = this.lwm2mConfigFormGroup.get('clientKey').value; + this.jsonAllConfig.client = clientSecurityConfigPSK; + this.lwm2mConfigFormGroup.patchValue({ + identityPSK: clientSecurityConfigPSK.identity, + clientCertificate: false + }, {emitEvent: true}); + break; + case SECURITY_CONFIG_MODE.RPK: + let clientSecurityConfigRPK = getDefaultClientSecurityConfigType(mode) as ClientSecurityConfigRPK; + clientSecurityConfigRPK.key = this.lwm2mConfigFormGroup.get('clientKey').value; + this.jsonAllConfig.client = clientSecurityConfigRPK; + this.lwm2mConfigFormGroup.patchValue({ + jsonAllConfig: this.jsonAllConfig, + clientCertificate: false + }, {emitEvent: true}) + break; + case SECURITY_CONFIG_MODE.X509: + let clientSecurityConfigX509 = getDefaultClientSecurityConfigType(mode) as ClientSecurityConfigX509; + this.jsonAllConfig.client = clientSecurityConfigX509; + this.lwm2mConfigFormGroup.patchValue({ + jsonAllConfig: this.jsonAllConfig, + clientCertificate: true + }, {emitEvent: true}) + break; + } + this.securityConfigClientUpdateValidators(mode); + } + + securityConfigClientUpdateValidators(mode: SECURITY_CONFIG_MODE): void { + switch (mode) { + case SECURITY_CONFIG_MODE.NO_SEC: + this.lwm2mConfigFormGroup.get('identityPSK').setValidators([]); + this.lwm2mConfigFormGroup.get('identityPSK').updateValueAndValidity(); + this.lwm2mConfigFormGroup.get('clientKey').setValidators([]); + this.lwm2mConfigFormGroup.get('clientKey').updateValueAndValidity(); + break; + case SECURITY_CONFIG_MODE.PSK: + this.lenMaxKeyClient = LEN_MAX_PSK; + this.lwm2mConfigFormGroup.get('identityPSK').setValidators([]); + this.lwm2mConfigFormGroup.get('identityPSK').updateValueAndValidity(); + this.lwm2mConfigFormGroup.get('clientKey').setValidators([Validators.required, Validators.pattern(KEY_IDENT_REGEXP_PSK)]); + this.lwm2mConfigFormGroup.get('clientKey').updateValueAndValidity(); + break; + case SECURITY_CONFIG_MODE.RPK: + this.lenMaxKeyClient = LEN_MAX_PUBLIC_KEY_RPK; + this.lwm2mConfigFormGroup.get('identityPSK').setValidators([]); + this.lwm2mConfigFormGroup.get('identityPSK').updateValueAndValidity(); + this.lwm2mConfigFormGroup.get('clientKey').setValidators([Validators.required, Validators.pattern(KEY_PUBLIC_REGEXP_PSK)]); + this.lwm2mConfigFormGroup.get('clientKey').updateValueAndValidity(); + break; + case SECURITY_CONFIG_MODE.X509: + this.lenMaxKeyClient = LEN_MAX_PUBLIC_KEY_RPK; + this.lwm2mConfigFormGroup.get('identityPSK').setValidators([]); + this.lwm2mConfigFormGroup.get('identityPSK').updateValueAndValidity(); + this.lwm2mConfigFormGroup.get('clientKey').setValidators([]); + this.lwm2mConfigFormGroup.get('clientKey').updateValueAndValidity(); + break; + } + } + + tabChanged = (tabChangeEvent: MatTabChangeEvent): void => { + if (this.tabIndexPrevious !== tabChangeEvent.index) this.upDateValueToJson(); + this.tabIndexPrevious = tabChangeEvent.index; + } + + upDateValueToJson(): void { + switch (this.tabIndexPrevious) { + case 0: + this.upDateValueToJsonTab_0(); + break; + case 1: + this.upDateValueToJsonTab_1(); + break; + case 2: + this.upDateValueToJsonTab_2(); + break; + } + } + + upDateValueToJsonTab_0(): void { + if (this.lwm2mConfigFormGroup !== null) { + if (!this.lwm2mConfigFormGroup.get('endPoint').pristine && this.lwm2mConfigFormGroup.get('endPoint').valid) { + this.data.endPoint = this.lwm2mConfigFormGroup.get('endPoint').value; + // Client mode == PSK + if (this.lwm2mConfigFormGroup.get('securityConfigClientMode').value === SECURITY_CONFIG_MODE.PSK) { + this.jsonAllConfig.client["endpoint"] = this.data.endPoint; + this.jsonAllConfig.client["endpoint"].markAsPristine({ + onlySelf: true + }); + this.upDateJsonAllConfig(); + } + } + /** only Client mode == PSK */ + if (!this.lwm2mConfigFormGroup.get('identityPSK').pristine && this.lwm2mConfigFormGroup.get('identityPSK').valid) { + this.lwm2mConfigFormGroup.get('identityPSK').markAsPristine({ + onlySelf: true + }); + this.updateIdentityPSK(); + } + /** only Client mode == PSK (len = 64) || RPK (len = 182) */ + if (!this.lwm2mConfigFormGroup.get('clientKey').pristine && this.lwm2mConfigFormGroup.get('clientKey').valid) { + this.lwm2mConfigFormGroup.get('clientKey').markAsPristine({ + onlySelf: true + }); + this.updateClientKey(); + } + } + } + + upDateValueToJsonTab_1(): void { + if (this.lwm2mConfigFormGroup !== null) { + if (this.bootstrapFormGroup !== null && !this.bootstrapFormGroup.pristine && this.bootstrapFormGroup.valid) { + this.jsonAllConfig.bootstrap.bootstrapServer = this.bootstrapFormGroup.value; + this.bootstrapFormGroup.markAsPristine({ + onlySelf: true + }); + this.upDateJsonAllConfig(); + } + + if (this.lwm2mServerFormGroup !== null && !this.lwm2mServerFormGroup.pristine && this.lwm2mServerFormGroup.valid) { + this.jsonAllConfig.bootstrap.lwm2mServer = this.lwm2mServerFormGroup.value; + this.lwm2mServerFormGroup.markAsPristine({ + onlySelf: true + }); + this.upDateJsonAllConfig(); + } + } + } + + upDateValueToJsonTab_2(): void { + if (!this.lwm2mConfigFormGroup.get(this.formControlNameJsonAllConfig).pristine && this.lwm2mConfigFormGroup.get(this.formControlNameJsonAllConfig).valid) { + this.jsonAllConfig = this.lwm2mConfigFormGroup.get(this.formControlNameJsonAllConfig).value; + this.lwm2mConfigFormGroup.get(this.formControlNameJsonAllConfig).markAsPristine({ + onlySelf: true + }); + } + } + + updateIdentityPSK(): void { + if (this.lwm2mConfigFormGroup.get('bootstrapServer').value['securityMode'] === SECURITY_CONFIG_MODE.PSK.toString()) { + this.lwm2mConfigFormGroup.get('bootstrapFormGroup').patchValue({ + clientPublicKeyOrId: this.lwm2mConfigFormGroup.get('identityPSK').value + }); + this.jsonAllConfig.client['identity'] = this.lwm2mConfigFormGroup.get('identityPSK').value; + this.upDateJsonAllConfig(); + } + if (this.lwm2mConfigFormGroup.get('lwm2mServer').value['securityMode'] === SECURITY_CONFIG_MODE.PSK.toString()) { + this.lwm2mConfigFormGroup.get('lwm2mServerFormGroup').patchValue({ + clientPublicKeyOrId: this.lwm2mConfigFormGroup.get('identityPSK').value + }); + this.jsonAllConfig.bootstrap.lwm2mServer.clientPublicKeyOrId = this.lwm2mConfigFormGroup.get('identityPSK').value; + this.upDateJsonAllConfig(); + } + } + + updateClientKey(): void { + this.jsonAllConfig.client["key"] = this.lwm2mConfigFormGroup.get('clientKey').value; + if (this.lwm2mConfigFormGroup.get('bootstrapServer').value['securityMode'] === SECURITY_CONFIG_MODE.PSK.toString()) { + this.lwm2mConfigFormGroup.get('bootstrapServer').patchValue({ + clientSecretKey: this.jsonAllConfig.client["key"] + }, {emitEvent: false}); + this.jsonAllConfig.bootstrap.bootstrapServer.clientSecretKey = this.jsonAllConfig.client["key"]; + } + if (this.lwm2mConfigFormGroup.get('lwm2mServer').value['securityMode'] === SECURITY_CONFIG_MODE.PSK.toString()) { + this.lwm2mConfigFormGroup.get('lwm2mServer').patchValue({ + clientSecretKey: this.jsonAllConfig.client["key"] + }, {emitEvent: false}); + this.jsonAllConfig.bootstrap.lwm2mServer.clientSecretKey = this.jsonAllConfig.client["key"]; + } + this.upDateJsonAllConfig(); + } + + upDateJsonAllConfig(): void { + this.data.jsonAllConfig = JSON.parse(JSON.stringify(this.jsonAllConfig)); + this.lwm2mConfigFormGroup.patchValue({ + jsonAllConfig: JSON.parse(JSON.stringify(this.jsonAllConfig)) + }, {emitEvent: false}); + this.lwm2mConfigFormGroup.markAsDirty(); + } + + upDateBootstrapFormGroup(): void { + this.data.jsonAllConfig = JSON.parse(JSON.stringify(this.jsonAllConfig)); + this.lwm2mConfigFormGroup.patchValue({ + jsonAllConfig: JSON.parse(JSON.stringify(this.jsonAllConfig)) + }, {emitEvent: false}); + this.lwm2mConfigFormGroup.markAsDirty(); + } + + initLwm2mConfigFormGroup(): FormGroup { + if (SECURITY_CONFIG_MODE[this.jsonAllConfig.client.securityConfigClientMode.toString()] === SECURITY_CONFIG_MODE.PSK) { + this.data.endPoint = this.jsonAllConfig.client['endpoint']; + } + return this.fb.group({ + securityConfigClientMode: [SECURITY_CONFIG_MODE[this.jsonAllConfig.client.securityConfigClientMode.toString()], []], + identityPSK: ['', []], + clientKey: ['', []], + clientCertificate: [false, []], + bootstrapServer: [this.jsonAllConfig.bootstrap[this.bootstrapServer], []], + lwm2mServer: [this.jsonAllConfig.bootstrap[this.lwm2mServer], []], + bootstrapFormGroup: this.getServerGroup(true), + lwm2mServerFormGroup: this.getServerGroup(false), + endPoint: [this.data.endPoint, []], + jsonAllConfig: [this.jsonAllConfig, []] + }); + } + + getServerGroup(bootstrapServerIs: boolean): FormGroup { + return this.fb.group({ + securityMode: [this.fb.control(SECURITY_CONFIG_MODE.NO_SEC), []], + clientPublicKeyOrId: ['', []], + clientSecretKey: ['', []] + }) + } + + save(): void { + this.upDateValueToJson(); + this.data.endPoint = this.lwm2mConfigFormGroup.get('endPoint').value.split('\"').join(''); + this.data.jsonAllConfig = this.jsonAllConfig; + if (this.lwm2mConfigFormGroup.get('securityConfigClientMode').value === SECURITY_CONFIG_MODE.PSK) { + this.data.endPoint = this.data.jsonAllConfig.client["identity"]; + } + this.dialogRef.close(this.data); + } + + cancel(): void { + this.dialogRef.close(undefined); + } +} + + diff --git a/ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config.models.ts b/ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config.models.ts new file mode 100644 index 0000000000..cd323e2f90 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config.models.ts @@ -0,0 +1,154 @@ +/// +/// Copyright © 2016-2020 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +export const JSON_ALL_CONFIG = 'jsonAllConfig'; +export const END_POINT = 'endPoint'; +export const DEFAULT_END_POINT = 'default_client_lwm2m_end_point_no_sec'; +export const BOOTSTRAP_SERVERS = 'servers'; +export const BOOTSTRAP_SERVER = 'bootstrapServer'; +export const LWM2M_SERVER = 'lwm2mServer'; +export const JSON_OBSERVE = 'jsonObserve'; +export const LEN_MAX_PSK = 64; +export const LEN_MAX_PRIVATE_KEY = 134; +export const LEN_MAX_PUBLIC_KEY_RPK = 182; +export const LEN_MAX_PUBLIC_KEY_X509 = 3000; +export const KEY_IDENT_REGEXP_PSK = /^[0-9a-fA-F]{64,64}$/; +export const KEY_PRIVATE_REGEXP = /^[0-9a-fA-F]{134,134}$/; +export const KEY_PUBLIC_REGEXP_PSK = /^[0-9a-fA-F]{182,182}$/; +export const KEY_PUBLIC_REGEXP_X509 = /^[0-9a-fA-F]{0,3000}$/; + +export interface DeviceCredentialsDialogLwm2mData { + jsonAllConfig?: SecurityConfigModels; + endPoint?: string; + isNew?: boolean; +} + +export enum SECURITY_CONFIG_MODE { + PSK = 'PSK', + RPK = 'RPK', + X509 = 'X509', + NO_SEC = 'NO_SEC' +} + +export const SECURITY_CONFIG_MODE_NAMES = new Map( + [ + [SECURITY_CONFIG_MODE.PSK, 'Pre-Shared Key'], + [SECURITY_CONFIG_MODE.RPK, 'Raw Public Key'], + [SECURITY_CONFIG_MODE.X509, 'X.509 Certificate'], + [SECURITY_CONFIG_MODE.NO_SEC, 'No Security'], + ] +); + +export type ClientSecurityConfigType = + ClientSecurityConfigPSK + | ClientSecurityConfigRPK + | ClientSecurityConfigX509 + | ClientSecurityConfigNO_SEC; + +export interface ClientSecurityConfigPSK { + securityConfigClientMode: string, + endpoint: string, + identity: string, + key: string +} + +export interface ClientSecurityConfigRPK { + securityConfigClientMode: string, + key: string +} + +export interface ClientSecurityConfigX509 { + securityConfigClientMode: string, + x509: boolean +} + +export interface ClientSecurityConfigNO_SEC { + securityConfigClientMode: string +} + +export interface ServerSecurityConfig { + securityMode: string, + clientPublicKeyOrId?: string, + clientSecretKey?: string +} + +interface BootstrapSecurityConfig { + bootstrapServer: ServerSecurityConfig, + lwm2mServer: ServerSecurityConfig +} + +export interface SecurityConfigModels { + client: ClientSecurityConfigType, + bootstrap: BootstrapSecurityConfig +} + +export function getDefaultClientSecurityConfigType(securityConfigMode: SECURITY_CONFIG_MODE, endPoint?: string): ClientSecurityConfigType { + let security: ClientSecurityConfigType; + switch (securityConfigMode) { + case SECURITY_CONFIG_MODE.PSK: + security = { + securityConfigClientMode: '', + endpoint: endPoint, + identity: endPoint, + key: '' + } + break; + case SECURITY_CONFIG_MODE.RPK: + security = { + securityConfigClientMode: '', + key: '' + } + break; + case SECURITY_CONFIG_MODE.X509: + security = { + securityConfigClientMode: '', + x509: true + } + break; + case SECURITY_CONFIG_MODE.NO_SEC: + security = { + securityConfigClientMode: '' + } + break; + } + security.securityConfigClientMode = securityConfigMode.toString(); + return security; +} + +export function getDefaultServerSecurityConfig(): ServerSecurityConfig { + return { + securityMode: SECURITY_CONFIG_MODE.NO_SEC.toString(), + clientPublicKeyOrId: '', + clientSecretKey: '' + } +} + +function getDefaultBootstrapSecurityConfig(): BootstrapSecurityConfig { + return { + bootstrapServer: getDefaultServerSecurityConfig(), + lwm2mServer: getDefaultServerSecurityConfig() + } +} + +export function getDefaultSecurityConfig(): SecurityConfigModels { + const securityConfigModels = { + client: getDefaultClientSecurityConfigType(SECURITY_CONFIG_MODE.NO_SEC), + bootstrap: getDefaultBootstrapSecurityConfig() + }; + return securityConfigModels; +} + + diff --git a/ui-ngx/src/app/shared/components/json-object-edit.component.ts b/ui-ngx/src/app/shared/components/json-object-edit.component.ts index 503b12c1a8..72c4505c0b 100644 --- a/ui-ngx/src/app/shared/components/json-object-edit.component.ts +++ b/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 } from '@core/utils'; +import { guid, isUndefined } from '@core/utils'; import { ResizeObserver } from '@juggle/resize-observer'; @Component({ @@ -59,21 +59,27 @@ export class JsonObjectEditComponent implements OnInit, ControlValueAccessor, Va @Input() fillHeight: boolean; - @Input() editorStyle: {[klass: string]: any}; + @Input() editorStyle: { [klass: string]: any }; + + @Input() sort: Function; private requiredValue: boolean; + get required(): boolean { return this.requiredValue; } + @Input() set required(value: boolean) { this.requiredValue = coerceBooleanProperty(value); } private readonlyValue: boolean; + get readonly(): boolean { return this.readonlyValue; } + @Input() set readonly(value: boolean) { this.readonlyValue = coerceBooleanProperty(value); @@ -218,8 +224,12 @@ export class JsonObjectEditComponent implements OnInit, ControlValueAccessor, Va this.contentValue = ''; this.objectValid = false; try { + if (this.modelValue) { - this.contentValue = JSON.stringify(this.modelValue, undefined, 2); + this.contentValue = JSON.stringify(this.modelValue, isUndefined(this.sort) ? undefined : + (key, value) => { + return this.sort(key, value) + }, 2); this.objectValid = true; } else { this.objectValid = !this.required; diff --git a/ui-ngx/src/app/shared/models/device.models.ts b/ui-ngx/src/app/shared/models/device.models.ts index ffeae2f56d..0f07cadd36 100644 --- a/ui-ngx/src/app/shared/models/device.models.ts +++ b/ui-ngx/src/app/shared/models/device.models.ts @@ -35,7 +35,7 @@ export enum DeviceProfileType { export enum DeviceTransportType { DEFAULT = 'DEFAULT', MQTT = 'MQTT', - // LWM2M = 'LWM2M' + LWM2M = 'LWM2M' } export enum MqttTransportPayloadType { @@ -76,7 +76,7 @@ export const deviceTransportTypeTranslationMap = new Map( [ [DeviceTransportType.DEFAULT, 'device-profile.transport-type-default-hint'], [DeviceTransportType.MQTT, 'device-profile.transport-type-mqtt-hint'], - // [DeviceTransportType.LWM2M, 'device-profile.transport-type-lwm2m-hint'] + [DeviceTransportType.LWM2M, 'device-profile.transport-type-lwm2m-hint'] ] ); @@ -121,13 +121,13 @@ export const deviceTransportTypeConfigurationInfoMap = new Map( [ [DeviceCredentialsType.ACCESS_TOKEN, 'Access token'], [DeviceCredentialsType.X509_CERTIFICATE, 'MQTT X.509'], - [DeviceCredentialsType.MQTT_BASIC, 'MQTT Basic'] + [DeviceCredentialsType.MQTT_BASIC, 'MQTT Basic'], + [DeviceCredentialsType.LWM2M_CREDENTIALS, 'LwM2M Credentials'] ] ); @@ -452,6 +454,8 @@ export interface DeviceCredentials extends BaseData { credentialsType: DeviceCredentialsType; credentialsId: string; credentialsValue: string; + credentialsLwKey: string; + credentialsLwValue: string; } export interface DeviceCredentialMQTTBasic { diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 86ac20bf35..b1dcbf97d5 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -872,6 +872,31 @@ "access-token-invalid": "Access token length must be from 1 to 20 characters.", "rsa-key": "RSA public key", "rsa-key-required": "RSA public key is required.", + "lwm2m-key": "LwM2M Security config key", + "lwm2m-key-required": "LwM2M Security config key is required.", + "lwm2m-value": "LwM2M Security config", + "lwm2m-value-required": "LwM2M Security config value is required.", + "lwm2m-endpoint": "Client endpoint/identity", + "lwm2m-security-info": "Security Config Info", + "lwm2m-value-edit": "Edit Security config", + "lwm2m-value-edit-tip": "Edit security config json editor", + "lwm2m-security-config": { + "identity": "Client Identity", + "client-key": "Client Key", + "required": " value is required.", + "endpoint": "Endpoint Client Name", + "mode": "Security config mode", + "client-tab": "Client Security Config", + "client-certificate": "Client certificate", + "bootstrap-tab": "Bootstrap Client", + "bootstrap-server": "Bootstrap Server", + "lwm2m-server": "LwM2M Server", + "client-publicKey-or-id": "Client Public Key or Id", + "client-secret-key": "Client Secret Key", + "config-json-tab": "Json Client Security Config", + "pattern_hex_dec_64": "must be hex decimal format and 64 characters", + "pattern_hex_dec_182": "must be hex decimal format and 182 characters" + }, "client-id": "Client ID", "client-id-pattern": "Contains invalid character.", "user-name": "User Name", @@ -1071,7 +1096,57 @@ "schedule-time": "Time", "schedule-time-from": "From", "schedule-time-to": "To", - "schedule-days-of-week-required": "At least one day of week should be selected." + "schedule-days-of-week-required": "At least one day of week should be selected.", + "lwm2m": { + "object-list": "Object list", + "object-list-empty": "No objects selected.", + "no-objects-matching": "No objects matching '{{object}}' were found.", + "valid-id-instance-no-min": "Instance number '{{instance}}' no validated. Min value='{{min}}'", + "valid-id-instance-no-max": "Instance number '{{instance}}' no validated. Max value='{{max}}'", + "model-tab": "LWM2M Model", + "add-instances-tip": "Add new instances", + "instances-list": "Instances list", + "instances-input": "Input Instance Id value", + "instances-input-holder": "Input Instance number...", + "resource-label": "Resource", + "observe-label": "Observe", + "attribute-label": "Attribute", + "telemetry-label": "Telemetry", + "key-name-label": "Key Name", + "is-observe-tip": "Is Observe", + "is-attr-tip": "Is Attribute", + "is-telemetry-tip": "Is Telemetry", + "key-name-tip": "Key Name", + "key-name": "Key Name", + "key-name_label": "Key Name in Camel format", + "required": " value is required.", + "mode": "Security config mode", + "pattern_hex_dec_64": "must be hex decimal format and 64 characters", + "pattern_hex_dec_134": "must be hex decimal format and 134 characters", + "pattern_hex_dec_182": "must be hex decimal format and 182 characters", + "pattern_hex_dec": "must be hex decimal format", + "bootstrap-tab": "Bootstrap", + "servers": "Servers", + "short-id": "Short ID", + "short-id-tip": "Short Server ID", + "lifetime": "Lifetime of the registration for this LwM2M client", + "default-min-period": "Minimum Period between two notifications (sec)", + "notif-if-disabled": "Notification Storing When Disabled or Offline", + "binding": "Binding", + "bootstrap-server": "Bootstrap Server", + "lwm2m-server": "LwM2M Server", + "server-host": "Host", + "server-host-tip": "Server Host", + "server-port": "Port", + "server-port-tip": "Server Port", + "server-public-key": "Server Public Key", + "server-public-key-tip": "Server Public Key only for X509, RPK", + "client-hold-off-time": "Hold Off Time", + "client-hold-off-time-tip": "Client Hold Off Time for use with a Bootstrap-Server only", + "bootstrap-server-account-timeout": "Account after the timeout", + "bootstrap-server-account-timeout-tip": "Bootstrap-Server Account after the timeout value given by this resource.", + "config-json-tab": "Json Config Profile Device" + } }, "dialog": { "close": "Close dialog" From 2fcc48555c39f40005d084fac7b088ebd979a15c Mon Sep 17 00:00:00 2001 From: nickAS21 <44275303+nickAS21@users.noreply.github.com> Date: Wed, 9 Dec 2020 22:37:47 +0200 Subject: [PATCH 003/249] Lwm2m 3 3 (#3829) * Lwm2m: Back -> add telemetry logLwm2m * Lwm2m: Back -> add telemetry logLwm2m * Lwm2m: SNAPSHOT 3.3.o * Lwm2m: SNAPSHOT 3.3.0 All --- common/transport/lwm2m/pom.xml | 2 +- msa/transport/lwm2m/pom.xml | 2 +- transport/lwm2m/pom.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/transport/lwm2m/pom.xml b/common/transport/lwm2m/pom.xml index 0e9d3d58cd..a904d1e12f 100644 --- a/common/transport/lwm2m/pom.xml +++ b/common/transport/lwm2m/pom.xml @@ -21,7 +21,7 @@ 4.0.0 org.thingsboard.common - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT transport org.thingsboard.common.transport diff --git a/msa/transport/lwm2m/pom.xml b/msa/transport/lwm2m/pom.xml index 039e50564a..dff835d58c 100644 --- a/msa/transport/lwm2m/pom.xml +++ b/msa/transport/lwm2m/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/transport/lwm2m/pom.xml b/transport/lwm2m/pom.xml index 23e037451a..60a2d29d58 100644 --- a/transport/lwm2m/pom.xml +++ b/transport/lwm2m/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT transport org.thingsboard.transport From 4bf0af9e78f8777f5e0a2a851c7d9dde96315024 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Thu, 10 Dec 2020 11:36:55 +0200 Subject: [PATCH 004/249] Lwm2m: add logLwm2m to start bootstrap --- .../secure/LwM2MBootstrapSecurityStore.java | 21 ++++- .../lwm2m/server/LwM2MSessionMsgListener.java | 2 +- .../server/LwM2MTransportContextServer.java | 90 ++++++++++++++++++- .../lwm2m/server/LwM2MTransportHandler.java | 12 +-- .../lwm2m/server/LwM2MTransportRequest.java | 6 +- .../lwm2m/server/LwM2MTransportService.java | 54 +++++------ 6 files changed, 146 insertions(+), 39 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java index 0b06f02547..b0fff4cf07 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java @@ -30,15 +30,21 @@ import org.eclipse.leshan.server.security.SecurityInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.transport.TransportService; +import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.transport.lwm2m.secure.LwM2MGetSecurityInfo; import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode; import org.thingsboard.server.transport.lwm2m.secure.ReadResultSecurityStore; +import org.thingsboard.server.transport.lwm2m.server.LwM2MSessionMsgListener; +import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportContextServer; +import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler; import org.thingsboard.server.transport.lwm2m.utils.TypeServer; import java.io.IOException; import java.security.GeneralSecurityException; import java.util.Arrays; import java.util.List; +import java.util.UUID; import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.*; @@ -52,6 +58,11 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { @Autowired LwM2MGetSecurityInfo lwM2MGetSecurityInfo; + @Autowired + public LwM2MTransportContextServer context; + + + public LwM2MBootstrapSecurityStore(EditableBootstrapConfigStore bootstrapConfigStore) { this.bootstrapConfigStore = bootstrapConfigStore; } @@ -147,16 +158,21 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { lwM2MBootstrapConfig.servers = mapper.readValue(bootstrapObject.get(SERVERS).toString(), LwM2MBootstrapServers.class); LwM2MServerBootstrap profileServerBootstrap = mapper.readValue(bootstrapObject.get(BOOTSTRAP_SERVER).toString(), LwM2MServerBootstrap.class); LwM2MServerBootstrap profileLwm2mServer = mapper.readValue(bootstrapObject.get(LWM2M_SERVER).toString(), LwM2MServerBootstrap.class); + UUID sessionUUiD = UUID.randomUUID(); + TransportProtos.SessionInfoProto sessionInfo = context.getValidateSessionInfo(store.getMsg(), sessionUUiD.getMostSignificantBits(), sessionUUiD.getLeastSignificantBits()); + context.getTransportService().registerAsyncSession(sessionInfo, new LwM2MSessionMsgListener(null, sessionInfo)); if (getValidatedSecurityMode(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap, lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer)) { lwM2MBootstrapConfig.bootstrapServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap); lwM2MBootstrapConfig.lwm2mServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer); + String logMsg = String.format(LOG_LW2M_INFO + ": getParametersBootstrap: %s Access connect client with bootstrap server.", store.getEndPoint()); + context.sentParametersOnThingsboard(context.getTelemetryMsgObject(logMsg), LwM2MTransportHandler.DEVICE_TELEMETRY_TOPIC, sessionInfo); return lwM2MBootstrapConfig; } else { log.error(" [{}] Different values SecurityMode between of client and profile.", store.getEndPoint()); log.error(LOG_LW2M_ERROR + " getParametersBootstrap: [{}] Different values SecurityMode between of client and profile.", store.getEndPoint()); - String logMsg = String.format(LOG_LW2M_ERROR + " getParametersBootstrap: %s Different values SecurityMode between of client and profile.", store.getEndPoint()); -// sentLogsToThingsboard(logMsg, store.getEndPoint()); + String logMsg = String.format(LOG_LW2M_ERROR + ": getParametersBootstrap: %s Different values SecurityMode between of client and profile.", store.getEndPoint()); + context.sentParametersOnThingsboard(context.getTelemetryMsgObject(logMsg), LwM2MTransportHandler.DEVICE_TELEMETRY_TOPIC, sessionInfo); return null; } } catch (JsonProcessingException e) { @@ -165,6 +181,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { } } + /** * Bootstrap security have to sync between (bootstrapServer in credential and bootstrapServer in profile) * and (lwm2mServer in credential and lwm2mServer in profile diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MSessionMsgListener.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MSessionMsgListener.java index bf88427879..2de352bc6c 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MSessionMsgListener.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MSessionMsgListener.java @@ -36,7 +36,7 @@ public class LwM2MSessionMsgListener implements GenericFutureListener TransportServiceCallback getPubAckCallbackSentAttrTelemetry(final T msg) { + return new TransportServiceCallback() { + @Override + public void onSuccess(Void dummy) { + log.trace("Success to publish msg: {}, dummy: {}", msg, dummy); + } + + @Override + public void onError(Throwable e) { + log.trace("[{}] Failed to publish msg: {}", msg, e); + } + }; + } + + public void sentParametersOnThingsboard(JsonElement msg, String topicName, TransportProtos.SessionInfoProto sessionInfo) { + try { + if (topicName.equals(LwM2MTransportHandler.DEVICE_ATTRIBUTES_TOPIC)) { + TransportProtos.PostAttributeMsg postAttributeMsg = adaptor.convertToPostAttributes(msg); + TransportServiceCallback call = this.getPubAckCallbackSentAttrTelemetry(postAttributeMsg); + transportService.process(sessionInfo, postAttributeMsg, this.getPubAckCallbackSentAttrTelemetry(call)); + } else if (topicName.equals(LwM2MTransportHandler.DEVICE_TELEMETRY_TOPIC)) { + TransportProtos.PostTelemetryMsg postTelemetryMsg = adaptor.convertToPostTelemetry(msg); + TransportServiceCallback call = this.getPubAckCallbackSentAttrTelemetry(postTelemetryMsg); + transportService.process(sessionInfo, postTelemetryMsg, this.getPubAckCallbackSentAttrTelemetry(call)); + } + } catch (AdaptorException e) { + log.error("[{}] Failed to process publish msg [{}]", topicName, e); + log.info("[{}] Closing current session due to invalid publish", topicName); + } + } + + public JsonObject getTelemetryMsgObject(String logMsg) { + JsonObject telemetries = new JsonObject(); + telemetries.addProperty(LOG_LW2M_TELEMETRY, logMsg); + return telemetries; + } + + /** + * @return - sessionInfo after access connect client + */ + public TransportProtos.SessionInfoProto getValidateSessionInfo(TransportProtos.ValidateDeviceCredentialsResponseMsg msg, long mostSignificantBits, long leastSignificantBits) { + return TransportProtos.SessionInfoProto.newBuilder() + .setNodeId(this.getNodeId()) + .setSessionIdMSB(mostSignificantBits) + .setSessionIdLSB(leastSignificantBits) + .setDeviceIdMSB(msg.getDeviceInfo().getDeviceIdMSB()) + .setDeviceIdLSB(msg.getDeviceInfo().getDeviceIdLSB()) + .setTenantIdMSB(msg.getDeviceInfo().getTenantIdMSB()) + .setTenantIdLSB(msg.getDeviceInfo().getTenantIdLSB()) + .setDeviceName(msg.getDeviceInfo().getDeviceName()) + .setDeviceType(msg.getDeviceInfo().getDeviceType()) + .setDeviceProfileIdLSB(msg.getDeviceInfo().getDeviceProfileIdLSB()) + .setDeviceProfileIdMSB(msg.getDeviceInfo().getDeviceProfileIdMSB()) + .build(); + } + } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportHandler.java index d922f2b1c5..e3c9fef985 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportHandler.java @@ -16,12 +16,10 @@ package org.thingsboard.server.transport.lwm2m.server; import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.gson.Gson; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.google.gson.JsonSyntaxException; +import com.google.gson.*; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.apache.qpid.proton.engine.Session; import org.eclipse.californium.core.network.config.NetworkConfig; import org.eclipse.leshan.core.model.ResourceModel; import org.eclipse.leshan.core.node.LwM2mNode; @@ -39,6 +37,11 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; +import org.thingsboard.server.common.transport.TransportService; +import org.thingsboard.server.common.transport.TransportServiceCallback; +import org.thingsboard.server.common.transport.adaptor.AdaptorException; +import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.transport.lwm2m.server.adaptors.LwM2MJsonAdaptor; import org.thingsboard.server.transport.lwm2m.server.client.AttrTelemetryObserveValue; import javax.annotation.PostConstruct; @@ -115,7 +118,6 @@ public class LwM2MTransportHandler{ @Autowired private LwM2MTransportService service; - @PostConstruct public void init() { LwM2mServerListener lwM2mServerListener = new LwM2mServerListener(lhServerCert, service); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java index 45a85b16bb..a7e13544db 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java @@ -229,7 +229,7 @@ public class LwM2MTransportRequest { if (isSuccess(((Response)response.getCoapResponse()).getCode())) { this.handleResponse(registration, request.getPath().toString(), response, request, lwM2MClient); if (request instanceof WriteRequest && ((WriteRequest) request).isReplaceRequest()) { - String msg = String.format(LOG_LW2M_INFO + " sendRequest Replace: CoapCde - %s Lwm2m code - %d name - %s Resource path - %s value - %s SendRequest to Client", + String msg = String.format(LOG_LW2M_INFO + ": sendRequest Replace: CoapCde - %s Lwm2m code - %d name - %s Resource path - %s value - %s SendRequest to Client", ((Response)response.getCoapResponse()).getCode(), response.getCode().getCode(), response.getCode().getName(), request.getPath().toString(), ((LwM2mSingleResource)((WriteRequest) request).getNode()).getValue().toString()); service.sentLogsToThingsboard(msg, registration.getId()); @@ -237,13 +237,13 @@ public class LwM2MTransportRequest { } } else { - String msg = String.format(LOG_LW2M_ERROR + " sendRequest: CoapCde - %s Lwm2m code - %d name - %s Resource path - %s SendRequest to Client", + String msg = String.format(LOG_LW2M_ERROR + ": sendRequest: CoapCde - %s Lwm2m code - %d name - %s Resource path - %s SendRequest to Client", ((Response)response.getCoapResponse()).getCode(), response.getCode().getCode(), response.getCode().getName(), request.getPath().toString()); service.sentLogsToThingsboard(msg, registration.getId()); log.error("[{}] - [{}] [{}] error SendRequest", ((Response)response.getCoapResponse()).getCode(), response.getCode(), request.getPath().toString()); } }, e -> { - String msg = String.format(LOG_LW2M_ERROR + " sendRequest: Resource path - %s msg error - %s SendRequest to Client", + String msg = String.format(LOG_LW2M_ERROR + ": sendRequest: Resource path - %s msg error - %s SendRequest to Client", request.getPath().toString(), e.toString()); service.sentLogsToThingsboard(msg, registration.getId()); log.error("[{}] - [{}] error SendRequest", request.getPath().toString(), e.toString()); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java index 7ff68b928c..370423ea4c 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java @@ -85,8 +85,8 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandle @ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' ) || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") public class LwM2MTransportService { - @Autowired - private LwM2MJsonAdaptor adaptor; +// @Autowired +// private LwM2MJsonAdaptor adaptor; @Autowired private TransportService transportService; @@ -263,9 +263,9 @@ public class LwM2MTransportService { log.error("[{}] [{}]", lwM2MClient.getEndPoint(), CLIENT_NOT_AUTHORIZED); this.closeClientSession(lwM2MClient.getRegistration()); } else { - sessionInfo = SessionInfoProto.newBuilder() + sessionInfo = SessionInfoProto.newBuilder() .setNodeId(this.context.getNodeId()) - .setSessionIdMSB(lwM2MClient.getSessionUuid().getMostSignificantBits()) + .setSessionIdMSB(lwM2MClient.getSessionUuid().getMostSignificantBits() ) .setSessionIdLSB(lwM2MClient.getSessionUuid().getLeastSignificantBits()) .setDeviceIdMSB(msg.getDeviceInfo().getDeviceIdMSB()) .setDeviceIdLSB(msg.getDeviceInfo().getDeviceIdLSB()) @@ -315,7 +315,7 @@ public class LwM2MTransportService { */ private void updateAttrTelemetry(Registration registration, boolean start, Set paths) { JsonObject attributes = new JsonObject(); - JsonObject telemetrys = new JsonObject(); + JsonObject telemetries = new JsonObject(); if (start) { // #1.1 JsonObject attributeClient = this.getAttributeClient(registration); @@ -327,7 +327,7 @@ public class LwM2MTransportService { } // #1.2 CountDownLatch cancelLatch = new CountDownLatch(1); - this.getParametersFromProfile(attributes, telemetrys, registration, paths); + this.getParametersFromProfile(attributes, telemetries, registration, paths); cancelLatch.countDown(); try { cancelLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); @@ -336,8 +336,8 @@ public class LwM2MTransportService { } if (attributes.getAsJsonObject().entrySet().size() > 0) this.updateParametersOnThingsboard(attributes, DEVICE_ATTRIBUTES_TOPIC, registration.getId()); - if (telemetrys.getAsJsonObject().entrySet().size() > 0) - this.updateParametersOnThingsboard(telemetrys, DEVICE_TELEMETRY_TOPIC, registration.getId()); + if (telemetries.getAsJsonObject().entrySet().size() > 0) + this.updateParametersOnThingsboard(telemetries, DEVICE_TELEMETRY_TOPIC, registration.getId()); } /** @@ -432,20 +432,22 @@ public class LwM2MTransportService { public void updateParametersOnThingsboard(JsonElement msg, String topicName, String registrationId) { SessionInfoProto sessionInfo = this.getValidateSessionInfo(registrationId); if (sessionInfo != null) { - try { - if (topicName.equals(LwM2MTransportHandler.DEVICE_ATTRIBUTES_TOPIC)) { - PostAttributeMsg postAttributeMsg = adaptor.convertToPostAttributes(msg); - TransportServiceCallback call = this.getPubAckCallbackSentAttrTelemetry(-1, postAttributeMsg); - transportService.process(sessionInfo, postAttributeMsg, call); - } else if (topicName.equals(LwM2MTransportHandler.DEVICE_TELEMETRY_TOPIC)) { - PostTelemetryMsg postTelemetryMsg = adaptor.convertToPostTelemetry(msg); - TransportServiceCallback call = this.getPubAckCallbackSentAttrTelemetry(-1, postTelemetryMsg); - transportService.process(sessionInfo, postTelemetryMsg, this.getPubAckCallbackSentAttrTelemetry(-1, call)); - } - } catch (AdaptorException e) { - log.error("[{}] Failed to process publish msg [{}]", topicName, e); - log.info("[{}] Closing current session due to invalid publish", topicName); - } + context.sentParametersOnThingsboard(msg, topicName, sessionInfo); +// try { +// if (topicName.equals(LwM2MTransportHandler.DEVICE_ATTRIBUTES_TOPIC)) { +// +//// PostAttributeMsg postAttributeMsg = adaptor.convertToPostAttributes(msg); +//// TransportServiceCallback call = this.getPubAckCallbackSentAttrTelemetry(-1, postAttributeMsg); +//// transportService.process(sessionInfo, postAttributeMsg, call); +// } else if (topicName.equals(LwM2MTransportHandler.DEVICE_TELEMETRY_TOPIC)) { +// PostTelemetryMsg postTelemetryMsg = adaptor.convertToPostTelemetry(msg); +// TransportServiceCallback call = this.getPubAckCallbackSentAttrTelemetry(-1, postTelemetryMsg); +// transportService.process(sessionInfo, postTelemetryMsg, this.getPubAckCallbackSentAttrTelemetry(-1, call)); +// } +// } catch (AdaptorException e) { +// log.error("[{}] Failed to process publish msg [{}]", topicName, e); +// log.info("[{}] Closing current session due to invalid publish", topicName); +// } } else { log.error("Client: [{}] updateParametersOnThingsboard [{}] sessionInfo ", registrationId, sessionInfo); } @@ -669,7 +671,7 @@ public class LwM2MTransportService { } else { log.error(LOG_LW2M_ERROR + ": Resource path - [{}] value - [{}] is not Writable and cannot be updated", path, value); - String logMsg = String.format(LOG_LW2M_ERROR + " attributeUpdate: Resource path - %s value - %s is not Writable and cannot be updated", path, value); + String logMsg = String.format(LOG_LW2M_ERROR + ": attributeUpdate: Resource path - %s value - %s is not Writable and cannot be updated", path, value); this.sentLogsToThingsboard(logMsg, lwM2MClient.getRegistration().getId()); } } @@ -990,9 +992,9 @@ public class LwM2MTransportService { public void sentLogsToThingsboard(String msg, String registrationId) { if (msg != null) { - JsonObject telemetrys = new JsonObject(); - telemetrys.addProperty(LOG_LW2M_TELEMETRY, msg); - this.updateParametersOnThingsboard(telemetrys, LwM2MTransportHandler.DEVICE_TELEMETRY_TOPIC, registrationId); + JsonObject telemetries = new JsonObject(); + telemetries.addProperty(LOG_LW2M_TELEMETRY, msg); + this.updateParametersOnThingsboard(telemetries, LwM2MTransportHandler.DEVICE_TELEMETRY_TOPIC, registrationId); } } From 85dd4a9416a0dc8938a94d62f6adcb2a62b8ba43 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Fri, 11 Dec 2020 19:25:51 +0200 Subject: [PATCH 005/249] Lwm2m: backEnd: add DelayedRequest --- .../secure/LwM2MBootstrapSecurityStore.java | 13 +- .../lwm2m/secure/LwM2MGetSecurityInfo.java | 6 +- .../lwm2m/server/LwM2MSessionMsgListener.java | 2 +- .../server/LwM2MTransportContextServer.java | 8 +- .../lwm2m/server/LwM2MTransportHandler.java | 90 ++-- .../lwm2m/server/LwM2MTransportRequest.java | 61 +-- .../lwm2m/server/LwM2MTransportService.java | 436 +++++++++++------- .../server/adaptors/LwM2MJsonAdaptor.java | 39 ++ .../adaptors/LwM2MTransportAdaptor.java | 4 + .../lwm2m/server/client/LwM2MClient.java | 49 +- .../secure/LwM2MSetSecurityStoreServer.java | 11 +- .../secure/LwM2mInMemorySecurityStore.java | 18 +- 12 files changed, 475 insertions(+), 262 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java index b0fff4cf07..a4e49fc546 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java @@ -30,7 +30,6 @@ import org.eclipse.leshan.server.security.SecurityInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Component; -import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.transport.lwm2m.secure.LwM2MGetSecurityInfo; import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode; @@ -46,7 +45,12 @@ import java.util.Arrays; import java.util.List; import java.util.UUID; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.*; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.BOOTSTRAP_SERVER; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.LOG_LW2M_ERROR; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.LOG_LW2M_INFO; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.LWM2M_SERVER; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.SERVERS; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.getBootstrapParametersFromThingsboard; @Slf4j @Component("LwM2MBootstrapSecurityStore") @@ -61,8 +65,6 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { @Autowired public LwM2MTransportContextServer context; - - public LwM2MBootstrapSecurityStore(EditableBootstrapConfigStore bootstrapConfigStore) { this.bootstrapConfigStore = bootstrapConfigStore; } @@ -161,7 +163,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { UUID sessionUUiD = UUID.randomUUID(); TransportProtos.SessionInfoProto sessionInfo = context.getValidateSessionInfo(store.getMsg(), sessionUUiD.getMostSignificantBits(), sessionUUiD.getLeastSignificantBits()); context.getTransportService().registerAsyncSession(sessionInfo, new LwM2MSessionMsgListener(null, sessionInfo)); - if (getValidatedSecurityMode(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap, lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer)) { + if (this.getValidatedSecurityMode(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap, lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer)) { lwM2MBootstrapConfig.bootstrapServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap); lwM2MBootstrapConfig.lwm2mServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer); String logMsg = String.format(LOG_LW2M_INFO + ": getParametersBootstrap: %s Access connect client with bootstrap server.", store.getEndPoint()); @@ -181,7 +183,6 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { } } - /** * Bootstrap security have to sync between (bootstrapServer in credential and bootstrapServer in profile) * and (lwm2mServer in credential and lwm2mServer in profile diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2MGetSecurityInfo.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2MGetSecurityInfo.java index ad63e21633..a02107ca45 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2MGetSecurityInfo.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2MGetSecurityInfo.java @@ -39,7 +39,11 @@ import java.util.Optional; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.*; +import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.NO_SEC; +import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.PSK; +import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.RPK; +import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.X509; + @Slf4j @Component("LwM2MGetSecurityInfo") diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MSessionMsgListener.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MSessionMsgListener.java index 2de352bc6c..97963038b8 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MSessionMsgListener.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MSessionMsgListener.java @@ -43,7 +43,7 @@ public class LwM2MSessionMsgListener implements GenericFutureListener 0) { - Lwm2mDeviceProfileTransportConfiguration lwm2mDeviceProfileTransportConfiguration = (Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration(); +// Lwm2mDeviceProfileTransportConfiguration lwm2mDeviceProfileTransportConfiguration = (Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration(); Object observeAttr = ((Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration()).getProperties(); try { ObjectMapper mapper = new ObjectMapper(); @@ -219,7 +226,6 @@ public class LwM2MTransportHandler{ public static JsonObject getBootstrapParametersFromThingsboard(DeviceProfile deviceProfile) { if (deviceProfile != null && ((Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration()).getProperties().size() > 0) { - Lwm2mDeviceProfileTransportConfiguration lwm2mDeviceProfileTransportConfiguration = (Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration(); Object bootstrap = ((Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration()).getProperties(); try { ObjectMapper mapper = new ObjectMapper(); @@ -278,7 +284,7 @@ public class LwM2MTransportHandler{ jsonValidFlesh = jsonValidFlesh.replaceAll("\n", ""); jsonValidFlesh = jsonValidFlesh.replaceAll("\t", ""); jsonValidFlesh = jsonValidFlesh.replaceAll(" ", ""); - String jsonValid = (jsonValidFlesh.substring(0, 1).equals("\"") && jsonValidFlesh.substring(jsonValidFlesh.length() - 1).equals("\"")) ? jsonValidFlesh.substring(1, jsonValidFlesh.length() - 1) : jsonValidFlesh; + String jsonValid = (jsonValidFlesh.charAt(0) == '"' && jsonValidFlesh.charAt(jsonValidFlesh.length() - 1) == '"') ? jsonValidFlesh.substring(1, jsonValidFlesh.length() - 1) : jsonValidFlesh; try { object = new JsonParser().parse(jsonValid).getAsJsonObject(); } catch (JsonSyntaxException e) { @@ -290,7 +296,7 @@ public class LwM2MTransportHandler{ public static Optional decode(byte[] byteArray) { try { - FSTConfiguration config = FSTConfiguration.createDefaultConfiguration();; + FSTConfiguration config = FSTConfiguration.createDefaultConfiguration(); T msg = (T) config.asObject(byteArray); return Optional.ofNullable(msg); } catch (IllegalArgumentException e) { @@ -301,14 +307,14 @@ public class LwM2MTransportHandler{ /** * Equals to Map for values - * @param map1 - * @param map2 - * @param - * @return + * @param map1 - + * @param map2 - + * @param - + * @return - true if equals */ public static > boolean mapsEquals(Map map1, Map map2) { - List values1 = new ArrayList(map1.values()); - List values2 = new ArrayList(map2.values()); + List values1 = new ArrayList<>(map1.values()); + List values2 = new ArrayList<>(map2.values()); Collections.sort(values1); Collections.sort(values2); return values1.equals(values2); @@ -322,14 +328,28 @@ public class LwM2MTransportHandler{ } public static String splitCamelCaseString(String s){ - LinkedList linkedListOut = new LinkedList(); + LinkedList linkedListOut = new LinkedList<>(); LinkedList linkedList = new LinkedList((Arrays.asList(s.split(" ")))); - linkedList.stream().forEach(str-> { + linkedList.forEach(str-> { String strOut = str.replaceAll("\\W", "").replaceAll("_", "").toUpperCase(); - if (strOut.length()>1) linkedListOut.add(strOut.substring(0, 1) + strOut.substring(1).toLowerCase()); + if (strOut.length()>1) linkedListOut.add(strOut.charAt(0) + strOut.substring(1).toLowerCase()); else linkedListOut.add(strOut); }); linkedListOut.set(0, (linkedListOut.get(0).substring(0, 1).toLowerCase() + linkedListOut.get(0).substring(1))); return StringUtils.join(linkedListOut, ""); } + + public static TransportServiceCallback getAckCallback(LwM2MClient lwM2MClient, int requestId, String typeTopic) { + return new TransportServiceCallback() { + @Override + public void onSuccess(Void dummy) { + log.trace("[{}] [{}] - requestId [{}] - EndPoint , Access AckCallback", typeTopic, requestId, lwM2MClient.getEndPoint()); + } + + @Override + public void onError(Throwable e) { + log.trace("[{}] Failed to publish msg", e.toString()); + } + }; + } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java index a7e13544db..295c3b9f64 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java @@ -113,8 +113,8 @@ public class LwM2MTransportRequest { * @param lwM2MClient * @param observation */ - public void sendAllRequest(LeshanServer lwServer, Registration registration, String target, String typeOper, - String contentFormatParam, LwM2MClient lwM2MClient, Observation observation, Object params, long timeoutInMs) { + public void sendAllRequest(LeshanServer lwServer, Registration registration, String target, String typeOper, String contentFormatParam, + LwM2MClient lwM2MClient, Observation observation, Object params, long timeoutInMs, boolean isDelayedUpdate) { ResultIds resultIds = new ResultIds(target); if (registration != null && resultIds.getObjectId() >= 0) { DownlinkRequest request = null; @@ -212,41 +212,47 @@ public class LwM2MTransportRequest { break; default: } - if (request != null) sendRequest(lwServer, registration, request, lwM2MClient, timeoutInMs); + if (request != null) + this.sendRequest(lwServer, registration, request, lwM2MClient, timeoutInMs, isDelayedUpdate); } } /** * - * @param lwServer - * @param registration - * @param request - * @param lwM2MClient - * @param timeoutInMs + * @param lwServer - + * @param registration - + * @param request - + * @param lwM2MClient - + * @param timeoutInMs - */ - private void sendRequest(LeshanServer lwServer, Registration registration, DownlinkRequest request, LwM2MClient lwM2MClient, long timeoutInMs) { + private void sendRequest(LeshanServer lwServer, Registration registration, DownlinkRequest request, LwM2MClient lwM2MClient, long timeoutInMs, boolean isDelayedUpdate) { lwServer.send(registration, request, timeoutInMs, (ResponseCallback) response -> { - if (isSuccess(((Response)response.getCoapResponse()).getCode())) { - this.handleResponse(registration, request.getPath().toString(), response, request, lwM2MClient); + if (isSuccess(((Response) response.getCoapResponse()).getCode())) { + this.handleResponse(registration, request.getPath().toString(), response, request, lwM2MClient, isDelayedUpdate); if (request instanceof WriteRequest && ((WriteRequest) request).isReplaceRequest()) { - String msg = String.format(LOG_LW2M_INFO + ": sendRequest Replace: CoapCde - %s Lwm2m code - %d name - %s Resource path - %s value - %s SendRequest to Client", - ((Response)response.getCoapResponse()).getCode(), response.getCode().getCode(), response.getCode().getName(), request.getPath().toString(), - ((LwM2mSingleResource)((WriteRequest) request).getNode()).getValue().toString()); + String delayedUpdateStr = ""; + if (isDelayedUpdate) { + delayedUpdateStr = " (delayedUpdate) "; + } + + String msg = String.format(LOG_LW2M_INFO + ": sendRequest Replace%s: CoapCde - %s Lwm2m code - %d name - %s Resource path - %s value - %s SendRequest to Client", + delayedUpdateStr, ((Response) response.getCoapResponse()).getCode(), response.getCode().getCode(), response.getCode().getName(), request.getPath().toString(), + ((LwM2mSingleResource) ((WriteRequest) request).getNode()).getValue().toString()); service.sentLogsToThingsboard(msg, registration.getId()); - log.info("[{}] - [{}] [{}] [{}] Update SendRequest", ((Response)response.getCoapResponse()).getCode(), response.getCode(), request.getPath().toString(), ((LwM2mSingleResource)((WriteRequest) request).getNode()).getValue()); + log.info("[{}] - [{}] [{}] [{}] Update SendRequest[{}]", ((Response) response.getCoapResponse()).getCode(), response.getCode(), request.getPath().toString(), + ((LwM2mSingleResource) ((WriteRequest) request).getNode()).getValue(), delayedUpdateStr); } - } - else { + } else { String msg = String.format(LOG_LW2M_ERROR + ": sendRequest: CoapCde - %s Lwm2m code - %d name - %s Resource path - %s SendRequest to Client", - ((Response)response.getCoapResponse()).getCode(), response.getCode().getCode(), response.getCode().getName(), request.getPath().toString()); + ((Response) response.getCoapResponse()).getCode(), response.getCode().getCode(), response.getCode().getName(), request.getPath().toString()); service.sentLogsToThingsboard(msg, registration.getId()); - log.error("[{}] - [{}] [{}] error SendRequest", ((Response)response.getCoapResponse()).getCode(), response.getCode(), request.getPath().toString()); + log.error("[{}] - [{}] [{}] error SendRequest", ((Response) response.getCoapResponse()).getCode(), response.getCode(), request.getPath().toString()); } }, e -> { String msg = String.format(LOG_LW2M_ERROR + ": sendRequest: Resource path - %s msg error - %s SendRequest to Client", request.getPath().toString(), e.toString()); service.sentLogsToThingsboard(msg, registration.getId()); - log.error("[{}] - [{}] error SendRequest", request.getPath().toString(), e.toString()); + log.error("[{}] - [{}] error SendRequest", request.getPath().toString(), e.toString()); }); } @@ -271,19 +277,18 @@ public class LwM2MTransportRequest { } return null; } catch (NumberFormatException e) { - String patn = "/" + objectId + "/" + instanceId + "/" + resourceId; - log.error("Path: [{}] type: [{}] value: [{}] errorMsg: [{}]]", patn, type, value, e.toString()); - return null; + String patn = "/" + objectId + "/" + instanceId + "/" + resourceId; + log.error("Path: [{}] type: [{}] value: [{}] errorMsg: [{}]]", patn, type, value, e.toString()); + return null; } } - private void handleResponse(Registration registration, final String path, LwM2mResponse response, DownlinkRequest request, LwM2MClient lwM2MClient) { + private void handleResponse(Registration registration, final String path, LwM2mResponse response, DownlinkRequest request, LwM2MClient lwM2MClient, boolean isDelayedUpdate) { executorService.submit(new Runnable() { @Override public void run() { - try { - sendResponse(registration, path, response, request, lwM2MClient); + sendResponse(registration, path, response, request, lwM2MClient, isDelayedUpdate); } catch (RuntimeException t) { log.error("[{}] endpoint [{}] path [{}] error Unable to after send response.", registration.getEndpoint(), path, t.toString()); } @@ -298,7 +303,7 @@ public class LwM2MTransportRequest { * @param response - * @param lwM2MClient - */ - private void sendResponse(Registration registration, String path, LwM2mResponse response, DownlinkRequest request, LwM2MClient lwM2MClient) { + private void sendResponse(Registration registration, String path, LwM2mResponse response, DownlinkRequest request, LwM2MClient lwM2MClient, boolean isDelayedUpdate) { if (response instanceof ObserveResponse) { service.onObservationResponse(registration, path, (ReadResponse) response); } else if (response instanceof CancelObservationResponse) { @@ -329,7 +334,7 @@ public class LwM2MTransportRequest { log.info("[{}] Path [{}] WriteAttributesResponse 8_Send", path, response); } else if (response instanceof WriteResponse) { log.info("[{}] Path [{}] WriteAttributesResponse 9_Send", path, response); - service.onAttributeUpdateOk(registration, path, (WriteRequest) request); + service.onAttributeUpdateOk(registration, path, (WriteRequest) request, isDelayedUpdate); } } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java index 370423ea4c..b37d419987 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java @@ -15,21 +15,23 @@ */ package org.thingsboard.server.transport.lwm2m.server; -import com.google.gson.*; +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.model.ResourceModel; import org.eclipse.leshan.core.node.LwM2mMultipleResource; import org.eclipse.leshan.core.node.LwM2mObject; import org.eclipse.leshan.core.node.LwM2mObjectInstance; -import org.eclipse.leshan.core.node.LwM2mSingleResource; -import org.eclipse.leshan.core.node.LwM2mResource; 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.observation.Observation; import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.core.request.WriteRequest; import org.eclipse.leshan.core.response.ReadResponse; -import org.eclipse.leshan.core.util.Hex; import org.eclipse.leshan.server.californium.LeshanServer; import org.eclipse.leshan.server.registration.Registration; import org.springframework.beans.factory.annotation.Autowired; @@ -38,36 +40,35 @@ import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.transport.TransportService; -import org.thingsboard.server.common.transport.TransportServiceCallback; import org.thingsboard.server.common.transport.adaptor.AdaptorException; import org.thingsboard.server.common.transport.adaptor.JsonConverter; import org.thingsboard.server.common.transport.service.DefaultTransportService; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.gen.transport.TransportProtos.ToTransportUpdateCredentialsProto; import org.thingsboard.server.gen.transport.TransportProtos.SessionEvent; import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; +import org.thingsboard.server.gen.transport.TransportProtos.ToTransportUpdateCredentialsProto; import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; -import org.thingsboard.server.gen.transport.TransportProtos.PostTelemetryMsg; -import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg; -import org.thingsboard.server.transport.lwm2m.server.adaptors.LwM2MJsonAdaptor; import org.thingsboard.server.transport.lwm2m.server.client.AttrTelemetryObserveValue; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import org.thingsboard.server.transport.lwm2m.server.client.ModelObject; -import org.thingsboard.server.transport.lwm2m.server.client.ResultsAnalyzerParameters; import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue; +import org.thingsboard.server.transport.lwm2m.server.client.ResultsAnalyzerParameters; import org.thingsboard.server.transport.lwm2m.server.secure.LwM2mInMemorySecurityStore; import javax.annotation.PostConstruct; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; -import java.util.UUID; -import java.util.Random; -import java.util.Map; import java.util.HashMap; -import java.util.Arrays; -import java.util.Set; import java.util.HashSet; +import java.util.List; +import java.util.Map; import java.util.NoSuchElementException; +import java.util.Objects; import java.util.Optional; +import java.util.Random; +import java.util.Set; +import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CountDownLatch; @@ -75,19 +76,26 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Predicate; import java.util.stream.Collectors; -import java.util.stream.Stream; -import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.*; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.CLIENT_NOT_AUTHORIZED; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.DEFAULT_TIMEOUT; +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_OBSERVE; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.GET_TYPE_OPER_READ; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.LOG_LW2M_ERROR; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.LOG_LW2M_INFO; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.LOG_LW2M_TELEMETRY; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.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.getAckCallback; @Slf4j @Service("LwM2MTransportService") @ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' ) || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") public class LwM2MTransportService { -// @Autowired -// private LwM2MJsonAdaptor adaptor; - @Autowired private TransportService transportService; @@ -100,10 +108,9 @@ public class LwM2MTransportService { @Autowired LwM2mInMemorySecurityStore lwM2mInMemorySecurityStore; - @PostConstruct public void init() { - context.getScheduler().scheduleAtFixedRate(() -> checkInactivityAndReportActivity(), new Random().nextInt((int) context.getCtxServer().getSessionReportTimeout()), context.getCtxServer().getSessionReportTimeout(), TimeUnit.MILLISECONDS); + context.getScheduler().scheduleAtFixedRate(this::checkInactivityAndReportActivity, new Random().nextInt((int) context.getCtxServer().getSessionReportTimeout()), context.getCtxServer().getSessionReportTimeout(), TimeUnit.MILLISECONDS); } /** @@ -122,7 +129,7 @@ public class LwM2MTransportService { * @param previousObsersations - may be null */ public void onRegistered(LeshanServer lwServer, Registration registration, Collection previousObsersations) { - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getlwM2MClient(lwServer, registration); + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.updateInSessionsLwM2MClient(lwServer, registration); if (lwM2MClient != null) { lwM2MClient.setLwM2MTransportService(this); lwM2MClient.setLwM2MTransportService(this); @@ -139,10 +146,10 @@ public class LwM2MTransportService { transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), null); this.sentLogsToThingsboard(LOG_LW2M_INFO + ": Client registration", registration.getId()); } else { - log.error("Client: [{}] onRegistered [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), sessionInfo); + log.error("Client: [{}] onRegistered [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); } } else { - log.error("Client: [{}] onRegistered [{}] name [{}] lwM2MClient ", registration.getId(), registration.getEndpoint(), lwM2MClient); + log.error("Client: [{}] onRegistered [{}] name [{}] lwM2MClient ", registration.getId(), registration.getEndpoint(), null); } } @@ -155,7 +162,7 @@ public class LwM2MTransportService { if (sessionInfo != null) { log.info("Client: [{}] updatedReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType()); } else { - log.error("Client: [{}] updatedReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), sessionInfo); + log.error("Client: [{}] updatedReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); } } @@ -180,7 +187,7 @@ public class LwM2MTransportService { } log.info("Client: [{}] unReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType()); } else { - log.error("Client: [{}] unReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), sessionInfo); + log.error("Client: [{}] unReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); } } @@ -193,10 +200,9 @@ public class LwM2MTransportService { * Those methods are called by the protocol stage thread pool, this means that execution MUST be done in a short delay, * * if you need to do long time processing use a dedicated thread pool. * - * @param registration + * @param registration - */ - - public void onAwakeDev(Registration registration) { + protected void onAwakeDev(Registration registration) { log.info("[{}] [{}] Received endpoint Awake version event", registration.getId(), registration.getEndpoint()); //TODO: associate endpointId with device information. } @@ -244,8 +250,8 @@ public class LwM2MTransportService { Arrays.stream(registration.getObjectLinks()).forEach(url -> { ResultIds pathIds = new ResultIds(url.getUrl()); if (pathIds.instanceId > -1 && pathIds.resourceId == -1) { - lwM2MTransportRequest.sendAllRequest(lwServer, registration, url.getUrl(), GET_TYPE_OPER_READ, - ContentFormat.TLV.getName(), lwM2MClient, null, null, this.context.getCtxServer().getTimeout()); + lwM2MTransportRequest.sendAllRequest(lwServer, registration, url.getUrl(), GET_TYPE_OPER_READ, ContentFormat.TLV.getName(), + lwM2MClient, null, null, this.context.getCtxServer().getTimeout(), false); } }); } @@ -256,16 +262,16 @@ public class LwM2MTransportService { */ private SessionInfoProto getValidateSessionInfo(String registrationId) { SessionInfoProto sessionInfo = null; - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getlwM2MClient(registrationId); + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(registrationId); if (lwM2MClient != null) { ValidateDeviceCredentialsResponseMsg msg = lwM2MClient.getCredentialsResponse(); if (msg == null || msg.getDeviceInfo() == null) { log.error("[{}] [{}]", lwM2MClient.getEndPoint(), CLIENT_NOT_AUTHORIZED); this.closeClientSession(lwM2MClient.getRegistration()); } else { - sessionInfo = SessionInfoProto.newBuilder() + sessionInfo = SessionInfoProto.newBuilder() .setNodeId(this.context.getNodeId()) - .setSessionIdMSB(lwM2MClient.getSessionUuid().getMostSignificantBits() ) + .setSessionIdMSB(lwM2MClient.getSessionUuid().getMostSignificantBits()) .setSessionIdLSB(lwM2MClient.getSessionUuid().getLeastSignificantBits()) .setDeviceIdMSB(msg.getDeviceInfo().getDeviceIdMSB()) .setDeviceIdLSB(msg.getDeviceInfo().getDeviceIdLSB()) @@ -284,21 +290,111 @@ public class LwM2MTransportService { /** * Add attribute/telemetry information from Client and credentials/Profile to client model and start observe * !!! if the resource has an observation, but no telemetry or attribute - the observation will not use - * #1 Client`s starting info to send to thingsboard - * #2 Sending Attribute Telemetry with value to thingsboard only once at the start of the connection - * #3 Start observe + * #1 Sending Attribute Telemetry with value to thingsboard only once at the start of the connection + * #2 Start observe * - * @param lwServer - LeshanServer - * @param registration - Registration LwM2M Client + * @param lwM2MClient - LwM2M Client */ - public void updatesAndSentModelParameter(LeshanServer lwServer, Registration registration) { + public void updatesAndSentModelParameter(LwM2MClient lwM2MClient) { // #1 -// this.setParametersToModelClient(registration, modelClient, deviceProfile); + this.updateAttrTelemetry(lwM2MClient.getRegistration(), true, null); // #2 - this.updateAttrTelemetry(registration, true, null); - // #3 - this.onSentObserveToClient(lwServer, registration); + this.onSentObserveToClient(lwM2MClient.getLwServer(), lwM2MClient.getRegistration()); + + } + + /** + * If there is a difference in values between the current resource values and the shared attribute values + * when the client connects to the server + * #1 get attributes name from profile include name resources in ModelObject if resource isWritable + * #2.1 #1 size > 0 => send Request getAttributes to thingsboard + * #2.2 #1 size == 0 => continue normal process + * + * @param lwM2MClient - LwM2M Client + */ + public void putDelayedUpdateResourcesThingsboard(LwM2MClient lwM2MClient) { + SessionInfoProto sessionInfo = this.getValidateSessionInfo(lwM2MClient.getRegistration().getId()); + if (sessionInfo != null) { + //#1.1 + #1.2 + List attrSharedNames = this.getNamesAttrFromProfileIsWritable(lwM2MClient); + if (attrSharedNames.size() > 0) { + //#2.1 + try { + TransportProtos.GetAttributeRequestMsg getAttributeMsg = context.getAdaptor().convertToGetAttributes(null, attrSharedNames); + lwM2MClient.getDelayedRequestsId().add(getAttributeMsg.getRequestId()); + transportService.process(sessionInfo, getAttributeMsg, getAckCallback(lwM2MClient, getAttributeMsg.getRequestId(), DEVICE_ATTRIBUTES_REQUEST)); + } catch (AdaptorException e) { + log.warn("Failed to decode get attributes request", e); + } + } + // #2.2 + else { + lwM2MClient.onSuccessDelayedRequests(null); + } + } + } + + /** + * Update resource value on client: if there is a difference in values between the current resource values and the shared attribute values + * #1 Get path resource by result attributesResponse + * #1.1 If two names have equal path => last time attribute + * #2.1 if there is a difference in values between the current resource values and the shared attribute values + * => sent to client Request Update of value (new value from shared attribute) + * and LwM2MClient.delayedRequests.add(path) + * #2.1 if there is not a difference in values between the current resource values and the shared attribute values + * + * @param attributesResponse - + * @param sessionInfo - + */ + public void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg attributesResponse, TransportProtos.SessionInfoProto sessionInfo) { + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(sessionInfo); + if (lwM2MClient.getDelayedRequestsId().contains(attributesResponse.getRequestId())) { + attributesResponse.getSharedAttributeListList().forEach(attr -> { + String path = this.getPathAttributeUpdate(sessionInfo, attr.getKv().getKey()); + // #1.1 + if (lwM2MClient.getDelayedRequests().keySet().contains(path) && attr.getTs() > lwM2MClient.getDelayedRequests().get(path).getTs()) { + lwM2MClient.getDelayedRequests().put(path, attr); + } else { + lwM2MClient.getDelayedRequests().put(path, attr); + } + }); + // #2.1 + lwM2MClient.getDelayedRequests().forEach((k, v)->{ + this.putDelayedUpdateResourcesClient (lwM2MClient, lwM2MClient.getResourceValue(k), v.getKv().getStringV(), k); + System.out.printf(" k: %s, v: %s%n, v1: %s%n", k, v.getKv().getStringV(), lwM2MClient.getResourceValue(k)); + }); + lwM2MClient.getDelayedRequestsId().remove(attributesResponse.getRequestId()); +// lwM2MClient.onSuccessDelayedRequests(); + } + } + + private void putDelayedUpdateResourcesClient (LwM2MClient lwM2MClient, Object valueOld, Object valueNew, String path){ + if (!valueOld.toString().equals(valueNew.toString())) { + lwM2MTransportRequest.sendAllRequest(lwM2MClient.getLwServer(), lwM2MClient.getRegistration(), path, POST_TYPE_OPER_WRITE_REPLACE, + ContentFormat.TLV.getName(), lwM2MClient, null, valueNew, this.context.getCtxServer().getTimeout(), + true); + } + } + + /** + * Get names and keyNames from profile attr resources IsWritable + * + * @param lwM2MClient - + * @return ArrayList names and keyNames from profile attr resources IsWritable + */ + private List getNamesAttrFromProfileIsWritable(LwM2MClient lwM2MClient) { + Set namesIsIsWritable = ConcurrentHashMap.newKeySet(); + AttrTelemetryObserveValue profile = lwM2mInMemorySecurityStore.getProfile(lwM2MClient.getProfileUuid()); + Set attrSet = new Gson().fromJson(profile.getPostAttributeProfile(), Set.class); + ConcurrentMap keyNamesMap = new Gson().fromJson(profile.getPostKeyNameProfile().toString(), ConcurrentHashMap.class); + ConcurrentMap keyNamesIsWritable = keyNamesMap.entrySet() + .stream() + .filter(e -> (attrSet.contains(e.getKey()) && lwM2MClient.getOperation(e.getKey()).isWritable())) + .collect(Collectors.toConcurrentMap(Map.Entry::getKey, Map.Entry::getValue)); + namesIsIsWritable.addAll(new HashSet<>(keyNamesIsWritable.values())); + keyNamesIsWritable.keySet().forEach(p -> namesIsIsWritable.add(lwM2MClient.getResourceName(p))); + return new ArrayList<>(namesIsIsWritable); } @@ -320,9 +416,7 @@ public class LwM2MTransportService { // #1.1 JsonObject attributeClient = this.getAttributeClient(registration); if (attributeClient != null) { - attributeClient.entrySet().forEach(p -> { - attributes.add(p.getKey(), p.getValue()); - }); + attributeClient.entrySet().forEach(p -> attributes.add(p.getKey(), p.getValue())); } } // #1.2 @@ -349,9 +443,7 @@ public class LwM2MTransportService { private JsonObject getAttributeClient(Registration registration) { if (registration.getAdditionalRegistrationAttributes().size() > 0) { JsonObject resNameValues = new JsonObject(); - registration.getAdditionalRegistrationAttributes().entrySet().forEach(entry -> { - resNameValues.addProperty(entry.getKey(), entry.getValue()); - }); + registration.getAdditionalRegistrationAttributes().forEach(resNameValues::addProperty); return resNameValues; } return null; @@ -371,7 +463,7 @@ public class LwM2MTransportService { ResultIds pathIds = new ResultIds(p.getAsString().toString()); if (pathIds.getResourceId() > -1) { if (path == null || path.contains(p.getAsString())) { - this.addParameters(pathIds, p.getAsString().toString(), attributes, registration); + this.addParameters(p.getAsString().toString(), attributes, registration); } } }); @@ -379,49 +471,27 @@ public class LwM2MTransportService { ResultIds pathIds = new ResultIds(p.getAsString().toString()); if (pathIds.getResourceId() > -1) { if (path == null || path.contains(p.getAsString())) { - this.addParameters(pathIds, p.getAsString().toString(), telemetry, registration); + this.addParameters(p.getAsString().toString(), telemetry, registration); } } }); } /** - * @param pathIds - path resource * @param parameters - JsonObject attributes/telemetry * @param registration - Registration LwM2M Client */ - private void addParameters(ResultIds pathIds, String path, JsonObject parameters, Registration registration) { - ModelObject modelObject = lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getModelObjects().get(pathIds.getObjectId()); + private void addParameters(String path, JsonObject parameters, Registration registration) { JsonObject names = lwM2mInMemorySecurityStore.getProfiles().get(lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getProfileUuid()).getPostKeyNameProfile(); String resName = String.valueOf(names.get(path)); - if (modelObject != null && resName != null && !resName.isEmpty()) { - String resValue = this.getResourceValue(modelObject, pathIds); + if (resName != null && !resName.isEmpty()) { + String resValue = lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getResourceValue(path); if (resValue != null) { parameters.addProperty(resName, resValue); } } } - /** - * @param modelObject - ModelObject of Client - * @param pathIds - path resource - * @return - value of Resource or null - */ - private String getResourceValue(ModelObject modelObject, ResultIds pathIds) { - String resValue = null; - if (modelObject.getInstances().get(pathIds.getInstanceId()) != null) { - LwM2mObjectInstance instance = modelObject.getInstances().get(pathIds.getInstanceId()); - if (instance.getResource(pathIds.getResourceId()) != null) { - resValue = instance.getResource(pathIds.getResourceId()).getType() == OPAQUE ? - Hex.encodeHexString((byte[]) instance.getResource(pathIds.getResourceId()).getValue()).toLowerCase() : - (instance.getResource(pathIds.getResourceId()).isMultiInstances()) ? - instance.getResource(pathIds.getResourceId()).getValues().toString() : - instance.getResource(pathIds.getResourceId()).getValue().toString(); - } - } - return resValue; - } - /** * Prepare Sent to Thigsboard callback - Attribute or Telemetry * @@ -433,53 +503,15 @@ public class LwM2MTransportService { SessionInfoProto sessionInfo = this.getValidateSessionInfo(registrationId); if (sessionInfo != null) { context.sentParametersOnThingsboard(msg, topicName, sessionInfo); -// try { -// if (topicName.equals(LwM2MTransportHandler.DEVICE_ATTRIBUTES_TOPIC)) { -// -//// PostAttributeMsg postAttributeMsg = adaptor.convertToPostAttributes(msg); -//// TransportServiceCallback call = this.getPubAckCallbackSentAttrTelemetry(-1, postAttributeMsg); -//// transportService.process(sessionInfo, postAttributeMsg, call); -// } else if (topicName.equals(LwM2MTransportHandler.DEVICE_TELEMETRY_TOPIC)) { -// PostTelemetryMsg postTelemetryMsg = adaptor.convertToPostTelemetry(msg); -// TransportServiceCallback call = this.getPubAckCallbackSentAttrTelemetry(-1, postTelemetryMsg); -// transportService.process(sessionInfo, postTelemetryMsg, this.getPubAckCallbackSentAttrTelemetry(-1, call)); -// } -// } catch (AdaptorException e) { -// log.error("[{}] Failed to process publish msg [{}]", topicName, e); -// log.info("[{}] Closing current session due to invalid publish", topicName); -// } } else { - log.error("Client: [{}] updateParametersOnThingsboard [{}] sessionInfo ", registrationId, sessionInfo); + log.error("Client: [{}] updateParametersOnThingsboard [{}] sessionInfo ", registrationId, null); } } - /** - * Sent to Thingsboard Attribute || Telemetry - * - * @param msgId - always == -1 - * @param msg - JsonObject: [{name: value}] - * @return - dummy - */ - private TransportServiceCallback getPubAckCallbackSentAttrTelemetry(final int msgId, final T msg) { - return new TransportServiceCallback() { - @Override - public void onSuccess(Void dummy) { - log.trace("Success to publish msg: {}, dummy: {}", msg, dummy); - } - - @Override - public void onError(Throwable e) { - log.trace("[{}] Failed to publish msg: {}", msg, e); - } - }; - } - - /** * Start observe * #1 - Analyze: * #1.1 path in observe == (attribute or telemetry) - * #1.2 recourseValue notNull * #2 Analyze after sent request (response): * #2.1 First: lwM2MTransportRequest.sendResponse -> ObservationListener.newObservation * #2.2 Next: ObservationListener.onResponse * @@ -499,15 +531,11 @@ public class LwM2MTransportService { p.getAsString().toString() : (getValidateObserve(attrTelemetryObserveValue.getPostTelemetryProfile(), p.getAsString().toString())) ? p.getAsString().toString() : null; if (target != null) { - // #1.2 - ResultIds pathIds = new ResultIds(target); - ModelObject modelObject = lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getModelObjects().get(pathIds.getObjectId()); // #2 - if (modelObject != null) { - if (getResourceValue(modelObject, pathIds) != null) { - lwM2MTransportRequest.sendAllRequest(lwServer, registration, target, GET_TYPE_OPER_OBSERVE, - null, null, null, null, this.context.getCtxServer().getTimeout()); - } + if (lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getResourceValue(target) != null) { + lwM2MTransportRequest.sendAllRequest(lwServer, registration, target, GET_TYPE_OPER_OBSERVE, + null, null, null, null, this.context.getCtxServer().getTimeout(), + false); } } }); @@ -516,9 +544,7 @@ public class LwM2MTransportService { public void setCancelObservations(LeshanServer lwServer, Registration registration) { if (registration != null) { Set observations = lwServer.getObservationService().getObservations(registration); - observations.forEach(observation -> { - this.setCancelObservationRecourse(lwServer, registration, observation.getPath().toString()); - }); + observations.forEach(observation -> this.setCancelObservationRecourse(lwServer, registration, observation.getPath().toString())); } } @@ -534,6 +560,7 @@ public class LwM2MTransportService { try { cancelLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { + e.printStackTrace(); } } @@ -599,7 +626,7 @@ public class LwM2MTransportService { private void onObservationSetResourcesValue(Registration registration, Object value, Map values, String path) { ResultIds resultIds = new ResultIds(path); // #1 - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getlwM2MClient(registration.getId()); + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(registration.getId()); ModelObject modelObject = lwM2MClient.getModelObjects().get(resultIds.getObjectId()); Map instancesModelObject = modelObject.getInstances(); LwM2mObjectInstance instanceOld = (instancesModelObject.get(resultIds.instanceId) != null) ? instancesModelObject.get(resultIds.instanceId) : null; @@ -607,7 +634,7 @@ public class LwM2MTransportService { LwM2mResource resourceOld = (resourcesOld != null && resourcesOld.get(resultIds.getResourceId()) != null) ? resourcesOld.get(resultIds.getResourceId()) : null; // #2 LwM2mResource resourceNew; - if (resourceOld.isMultiInstances()) { + if (Objects.requireNonNull(resourceOld).isMultiInstances()) { resourceNew = LwM2mMultipleResource.newResource(resultIds.getResourceId(), values, resourceOld.getType()); } else { resourceNew = LwM2mSingleResource.newResource(resultIds.getResourceId(), value, resourceOld.getType()); @@ -628,8 +655,9 @@ public class LwM2MTransportService { try { respLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); } catch (InterruptedException ex) { + ex.printStackTrace(); } - Set paths = new HashSet(); + Set paths = new HashSet<>(); paths.add(path); this.updateAttrTelemetry(registration, false, paths); } @@ -643,37 +671,36 @@ public class LwM2MTransportService { } /** - * Update - sent request in change value resources in Client (path to resources from profile by keyName) - * Only fo resources W - * Delete - nothing + * Update - sent request in change value resources in Client + * Path to resources from profile equal keyName or from ModelObject equal name + * Only for resources: isWritable && isPresent as attribute in profile -> AttrTelemetryObserveValue (format: CamelCase) + * Delete - nothing * * - * @param msg - - * @param sessionInfo - + * @param msg - */ - public void onAttributeUpdate(TransportProtos.AttributeUpdateNotificationMsg msg, SessionInfoProto sessionInfo) { + public void onAttributeUpdate(TransportProtos.AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo) { if (msg.getSharedUpdatedCount() > 0) { JsonElement el = JsonConverter.toJson(msg); el.getAsJsonObject().entrySet().forEach(de -> { - String profilePath = lwM2mInMemorySecurityStore.getProfiles().get(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())) - .getPostKeyNameProfile().getAsJsonObject().entrySet().stream() - .filter(e -> e.getValue().getAsString().equals(de.getKey())).findFirst().map(Map.Entry::getKey) - .orElse(""); - String path = !profilePath.isEmpty() ? profilePath : this.getPathAttributeUpdate(sessionInfo, de.getKey()); - if (path != null) { - ResultIds resultIds = new ResultIds(path); - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getSession(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())).entrySet().iterator().next().getValue(); - ResourceModel.Operations operations = lwM2MClient.getModelObjects().get(resultIds.getObjectId()).getObjectModel().resources.get(resultIds.getResourceId()).operations; - String value = ((JsonPrimitive) de.getValue()).getAsString(); - if (operations.isWritable()) { + String path = this.getPathAttributeUpdate(sessionInfo, de.getKey()); + String value = de.getValue().getAsString(); + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getSession(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())).entrySet().iterator().next().getValue(); + AttrTelemetryObserveValue profile = lwM2mInMemorySecurityStore.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); + if (path != null && validatePathInAttrProfile(profile.getPostAttributeProfile(), path)) { + if (lwM2MClient.getOperation(path).isWritable()) { lwM2MTransportRequest.sendAllRequest(lwM2MClient.getLwServer(), lwM2MClient.getRegistration(), path, POST_TYPE_OPER_WRITE_REPLACE, - ContentFormat.TLV.getName(), lwM2MClient, null, value, this.context.getCtxServer().getTimeout()); + ContentFormat.TLV.getName(), lwM2MClient, null, value, this.context.getCtxServer().getTimeout(), + false); log.info("[{}] path onAttributeUpdate", path); - } - else { + } else { log.error(LOG_LW2M_ERROR + ": Resource path - [{}] value - [{}] is not Writable and cannot be updated", path, value); String logMsg = String.format(LOG_LW2M_ERROR + ": attributeUpdate: Resource path - %s value - %s is not Writable and cannot be updated", path, value); this.sentLogsToThingsboard(logMsg, lwM2MClient.getRegistration().getId()); } + } else { + log.error(LOG_LW2M_ERROR + ": Attribute name - [{}] value - [{}] is not present as attribute in profile and cannot be updated", de.getKey(), value); + String logMsg = String.format(LOG_LW2M_ERROR + ": attributeUpdate: attribute name - %s value - %s is not present as attribute in profile and cannot be updated", de.getKey(), value); + this.sentLogsToThingsboard(logMsg, lwM2MClient.getRegistration().getId()); } }); } else if (msg.getSharedDeletedCount() > 0) { @@ -681,38 +708,86 @@ public class LwM2MTransportService { } } - private String getPathAttributeUpdate(SessionInfoProto sessionInfo, String keyName) { + /** + * Get path to resource from profile equal keyName or from ModelObject equal name + * Only for resource: isWritable && isPresent as attribute in profile -> AttrTelemetryObserveValue (format: CamelCase) + * + * @param sessionInfo - + * @param name - + * @return + */ + private String getPathAttributeUpdate(TransportProtos.SessionInfoProto sessionInfo, String name) { + String profilePath = this.getPathAttributeUpdateProfile(sessionInfo, name); + return !profilePath.isEmpty() ? profilePath : this.getPathAttributeUpdateModelObject(sessionInfo, name); + } + + /** + * @param postAttributeProfile - + * @param path - + * @return true if path isPresent in postAttributeProfile + */ + private boolean validatePathInAttrProfile(JsonArray postAttributeProfile, String path) { + Set attributesSet = new Gson().fromJson(postAttributeProfile, Set.class); + return attributesSet.stream().filter(p -> p.equals(path)).findFirst().isPresent(); + } + + + /** + * Get path to resource from profile equal keyName + * + * @param sessionInfo - + * @param name - + * @return + */ + private String getPathAttributeUpdateProfile(TransportProtos.SessionInfoProto sessionInfo, String name) { + AttrTelemetryObserveValue profile = lwM2mInMemorySecurityStore.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); + return profile.getPostKeyNameProfile().getAsJsonObject().entrySet().stream() + .filter(e -> e.getValue().getAsString().equals(name)).findFirst().map(Map.Entry::getKey) + .orElse(""); + } + + /** + * Get path to resource from ModelObject equal name + * + * @param name - + * @return true if name isPresent as Resource name (usual format) in ResourceModel + */ + private String getPathAttributeUpdateModelObject(TransportProtos.SessionInfoProto sessionInfo, String name) { try { LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getSession(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())).entrySet().iterator().next().getValue(); - Predicate> predicateRes = res -> keyName.equals(splitCamelCaseString(res.getValue().name)); + Predicate> predicateRes = res -> name.equals(res.getValue().name); Predicate> predicateObj = (obj -> { return obj.getValue().getObjectModel().resources.entrySet().stream().filter(predicateRes).findFirst().isPresent(); }); - Stream> objectStream = lwM2MClient.getModelObjects().entrySet().stream().filter(predicateObj); - Predicate> predicateResFinal = (objectStream.count() > 0) ? predicateRes : res -> keyName.equals(res.getValue().name); - Predicate> predicateObjFinal = (obj -> { - return obj.getValue().getObjectModel().resources.entrySet().stream().filter(predicateResFinal).findFirst().isPresent(); - }); - Map.Entry object = lwM2MClient.getModelObjects().entrySet().stream().filter(predicateObjFinal).findFirst().get(); + Map.Entry object = lwM2MClient.getModelObjects().entrySet().stream().filter(predicateObj).findFirst().get(); ModelObject modelObject = object.getValue(); LwM2mObjectInstance instance = modelObject.getInstances().entrySet().stream().findFirst().get().getValue(); - ResourceModel resource = modelObject.getObjectModel().resources.entrySet().stream().filter(predicateResFinal).findFirst().get().getValue(); + ResourceModel resource = modelObject.getObjectModel().resources.entrySet().stream().filter(predicateRes).findFirst().get().getValue(); return new LwM2mPath(object.getKey(), instance.getId(), resource.id).toString(); } catch (NoSuchElementException e) { - log.error("[{}] keyName [{}]", keyName, e.toString()); + log.error("[{}] keyName [{}]", name, e.toString()); return null; } } - public void onAttributeUpdateOk(Registration registration, String path, WriteRequest request) { + /** + * Update resource (attribute) value on thingsboard after update value in client + * + * @param registration - + * @param path - + * @param request - + */ + public void onAttributeUpdateOk(Registration registration, String path, WriteRequest request, boolean isDelayedUpdate) { ResultIds resultIds = new ResultIds(path); - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getlwM2MClient(registration.getId()); + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(registration.getId()); LwM2mResource resource = lwM2MClient.getModelObjects().get(resultIds.getObjectId()).getInstances().get(resultIds.getInstanceId()).getResource(resultIds.getResourceId()); if (resource.isMultiInstances()) { this.onObservationSetResourcesValue(registration, null, ((LwM2mSingleResource) request.getNode()).getValues(), path); } else { this.onObservationSetResourcesValue(registration, ((LwM2mSingleResource) request.getNode()).getValue(), null, path); } + + if (isDelayedUpdate) lwM2MClient.onSuccessDelayedRequests (request.getPath().toString()); } /** @@ -781,24 +856,24 @@ public class LwM2MTransportService { * @param deviceProfile - */ public void onDeviceUpdateChangeProfile(String registrationId, DeviceProfile deviceProfile) { - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getlwM2MClient(registrationId); + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(registrationId); AttrTelemetryObserveValue attrTelemetryObserveValueOld = lwM2mInMemorySecurityStore.getProfiles().get(lwM2MClient.getProfileUuid()); if (lwM2mInMemorySecurityStore.addUpdateProfileParameters(deviceProfile)) { LeshanServer lwServer = lwM2MClient.getLwServer(); Registration registration = lwM2mInMemorySecurityStore.getByRegistration(registrationId); // #1 JsonArray attributeOld = attrTelemetryObserveValueOld.getPostAttributeProfile(); - Set attributeSetOld = new Gson().fromJson(attributeOld, Set.class); + Set attributeSetOld = new Gson().fromJson(attributeOld, Set.class); JsonArray telemetryOld = attrTelemetryObserveValueOld.getPostTelemetryProfile(); - Set telemetrySetOld = new Gson().fromJson(telemetryOld, Set.class); + Set telemetrySetOld = new Gson().fromJson(telemetryOld, Set.class); JsonArray observeOld = attrTelemetryObserveValueOld.getPostObserveProfile(); JsonObject keyNameOld = attrTelemetryObserveValueOld.getPostKeyNameProfile(); AttrTelemetryObserveValue attrTelemetryObserveValueNew = lwM2mInMemorySecurityStore.getProfiles().get(deviceProfile.getUuidId()); JsonArray attributeNew = attrTelemetryObserveValueNew.getPostAttributeProfile(); - Set attributeSetNew = new Gson().fromJson(attributeNew, Set.class); + Set attributeSetNew = new Gson().fromJson(attributeNew, Set.class); JsonArray telemetryNew = attrTelemetryObserveValueNew.getPostTelemetryProfile(); - Set telemetrySetNew = new Gson().fromJson(telemetryNew, Set.class); + Set telemetrySetNew = new Gson().fromJson(telemetryNew, Set.class); JsonArray observeNew = attrTelemetryObserveValueNew.getPostObserveProfile(); JsonObject keyNameNew = attrTelemetryObserveValueNew.getPostKeyNameProfile(); // #2 @@ -841,8 +916,8 @@ public class LwM2MTransportService { // #5.1 if (!observeOld.equals(observeNew)) { - Set observeSetOld = new Gson().fromJson(observeOld, Set.class); - Set observeSetNew = new Gson().fromJson(observeNew, Set.class); + Set observeSetOld = new Gson().fromJson(observeOld, Set.class); + Set observeSetNew = new Gson().fromJson(observeNew, Set.class); //#5.2 add // path Attr/Telemetry includes newObserve attributeSetOld.addAll(telemetrySetOld); @@ -884,7 +959,7 @@ public class LwM2MTransportService { Set paths = keyNameNew.entrySet() .stream() .filter(e -> !e.getValue().equals(keyNameOld.get(e.getKey()))) - .collect(Collectors.toMap(map -> map.getKey(), map -> map.getValue())).keySet(); + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)).keySet(); analyzerParameters.setPathPostParametersAdd(paths); return analyzerParameters; } @@ -892,7 +967,7 @@ public class LwM2MTransportService { private ResultsAnalyzerParameters getAnalyzerParametersIn(Set parametersObserve, Set parameters) { ResultsAnalyzerParameters analyzerParameters = new ResultsAnalyzerParameters(); analyzerParameters.setPathPostParametersAdd(parametersObserve - .stream().filter(p -> parameters.contains(p)).collect(Collectors.toSet())); + .stream().filter(parameters::contains).collect(Collectors.toSet())); return analyzerParameters; } @@ -906,23 +981,25 @@ public class LwM2MTransportService { * @param targets - path Resources == [ "/2/0/0", "/2/0/1"] */ private void updateResourceValueObserve(LeshanServer lwServer, Registration registration, LwM2MClient lwM2MClient, Set targets, String typeOper) { - targets.stream().forEach(target -> { + targets.forEach(target -> { ResultIds pathIds = new ResultIds(target); if (pathIds.resourceId >= 0 && lwM2MClient.getModelObjects().get(pathIds.getObjectId()) .getInstances().get(pathIds.getInstanceId()).getResource(pathIds.getResourceId()).getValue() != null) { if (GET_TYPE_OPER_READ.equals(typeOper)) { lwM2MTransportRequest.sendAllRequest(lwServer, registration, target, typeOper, - ContentFormat.TLV.getName(), null, null, null, this.context.getCtxServer().getTimeout()); + ContentFormat.TLV.getName(), null, null, null, this.context.getCtxServer().getTimeout(), + false); } else if (GET_TYPE_OPER_OBSERVE.equals(typeOper)) { lwM2MTransportRequest.sendAllRequest(lwServer, registration, target, typeOper, - null, null, null, null, this.context.getCtxServer().getTimeout()); + null, null, null, null, this.context.getCtxServer().getTimeout(), + false); } } }); } private void cancelObserveIsValue(LeshanServer lwServer, Registration registration, Set paramAnallyzer) { - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getlwM2MClient(registration.getId()); + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(registration.getId()); paramAnallyzer.forEach(p -> { if (this.getResourceValue(lwM2MClient, p) != null) { this.setCancelObservationRecourse(lwServer, registration, p); @@ -937,7 +1014,6 @@ public class LwM2MTransportService { if (pathIds.getResourceId() > -1) { LwM2mResource resource = lwM2MClient.getModelObjects().get(pathIds.getObjectId()).getInstances().get(pathIds.getInstanceId()).getResource(pathIds.getResourceId()); if (resource.isMultiInstances()) { - Map values = resource.getValues(); if (resource.getValues().size() > 0) { resourceValue = new ResourceValue(); resourceValue.setMultiInstances(resource.isMultiInstances()); @@ -961,7 +1037,8 @@ public class LwM2MTransportService { */ public void doTrigger(LeshanServer lwServer, Registration registration, String path) { lwM2MTransportRequest.sendAllRequest(lwServer, registration, path, POST_TYPE_OPER_EXECUTE, - ContentFormat.TLV.getName(), null, null, null, this.context.getCtxServer().getTimeout()); + ContentFormat.TLV.getName(), null, null, null, this.context.getCtxServer().getTimeout(), + false); } /** @@ -979,6 +1056,7 @@ public class LwM2MTransportService { /** * Deregister session in transport + * * @param sessionInfo - lwm2m client */ private void doDisconnect(SessionInfoProto sessionInfo) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/adaptors/LwM2MJsonAdaptor.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/adaptors/LwM2MJsonAdaptor.java index 47dbe563a2..47c7c01b23 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/adaptors/LwM2MJsonAdaptor.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/adaptors/LwM2MJsonAdaptor.java @@ -24,6 +24,12 @@ import org.thingsboard.server.common.transport.adaptor.AdaptorException; import org.thingsboard.server.common.transport.adaptor.JsonConverter; import org.thingsboard.server.gen.transport.TransportProtos; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Random; +import java.util.Set; + @Slf4j @Component("LwM2MJsonAdaptor") @ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' )|| ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") @@ -46,4 +52,37 @@ public class LwM2MJsonAdaptor implements LwM2MTransportAdaptor { throw new AdaptorException(ex); } } + + @Override + public TransportProtos.GetAttributeRequestMsg convertToGetAttributes(List clientKeys, List sharedKeys) throws AdaptorException { + return processGetAttributeRequestMsg(clientKeys, sharedKeys); + } + + protected TransportProtos.GetAttributeRequestMsg processGetAttributeRequestMsg(List clientKeys, List sharedKeys) throws AdaptorException { + try { + TransportProtos.GetAttributeRequestMsg.Builder result = TransportProtos.GetAttributeRequestMsg.newBuilder(); + Random random = new Random(); + result.setRequestId(random.nextInt()); + if (clientKeys != null) { + result.addAllClientAttributeNames(clientKeys); + } + if (sharedKeys != null) { + result.addAllSharedAttributeNames(sharedKeys); + } + return result.build(); + } catch (RuntimeException e) { + log.warn("Failed to decode get attributes request", e); + throw new AdaptorException(e); + } + } + + private Set toStringSet(JsonElement requestBody, String name) { + JsonElement element = requestBody.getAsJsonObject().get(name); + if (element != null) { + return new HashSet<>(Arrays.asList(element.getAsString().split(","))); + } else { + return null; + } + } + } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/adaptors/LwM2MTransportAdaptor.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/adaptors/LwM2MTransportAdaptor.java index d4d54f4df8..f1672d2039 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/adaptors/LwM2MTransportAdaptor.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/adaptors/LwM2MTransportAdaptor.java @@ -19,9 +19,13 @@ import com.google.gson.JsonElement; import org.thingsboard.server.common.transport.adaptor.AdaptorException; import org.thingsboard.server.gen.transport.TransportProtos; +import java.util.List; + public interface LwM2MTransportAdaptor { TransportProtos.PostTelemetryMsg convertToPostTelemetry(JsonElement jsonElement) throws AdaptorException; TransportProtos.PostAttributeMsg convertToPostAttributes(JsonElement jsonElement) throws AdaptorException; + + TransportProtos.GetAttributeRequestMsg convertToGetAttributes(List clientKeys, List sharedKeys) throws AdaptorException; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java index 3a84a637ac..a28d7257d5 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java @@ -18,12 +18,15 @@ package org.thingsboard.server.transport.lwm2m.server.client; import lombok.Data; 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.LwM2mObjectInstance; import org.eclipse.leshan.core.response.LwM2mResponse; import org.eclipse.leshan.core.response.ReadResponse; +import org.eclipse.leshan.core.util.Hex; import org.eclipse.leshan.server.californium.LeshanServer; import org.eclipse.leshan.server.registration.Registration; import org.eclipse.leshan.server.security.SecurityInfo; +import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportService; import org.thingsboard.server.transport.lwm2m.server.ResultIds; @@ -35,6 +38,8 @@ import java.util.Collection; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; +import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE; + @Slf4j @Data public class LwM2MClient implements Cloneable { @@ -53,6 +58,8 @@ public class LwM2MClient implements Cloneable { private Map attributes; private Map modelObjects; private Set pendingRequests; + private Map delayedRequests; + private Set delayedRequestsId; private Map responses; public Object clone() throws CloneNotSupportedException { @@ -67,6 +74,8 @@ public class LwM2MClient implements Cloneable { this.attributes = (attributes != null && attributes.size() > 0) ? attributes : new ConcurrentHashMap(); this.modelObjects = (modelObjects != null && modelObjects.size() > 0) ? modelObjects : new ConcurrentHashMap(); this.pendingRequests = ConcurrentHashMap.newKeySet(); + this.delayedRequests = new ConcurrentHashMap<>(); + this.delayedRequestsId = ConcurrentHashMap.newKeySet(); this.profileUuid = profileUuid; /** * Key , response instance -> resources: value...> @@ -84,7 +93,7 @@ public class LwM2MClient implements Cloneable { this.pendingRequests.remove(path); if (this.pendingRequests.size() == 0) { this.initValue(); - this.lwM2MTransportService.updatesAndSentModelParameter(this.lwServer, this.registration); + this.lwM2MTransportService.putDelayedUpdateResourcesThingsboard(this); } } @@ -104,4 +113,42 @@ public class LwM2MClient implements Cloneable { } }); } + + public void onSuccessDelayedRequests (String path) { + if (path != null) this.delayedRequests.remove(path); + if (this.delayedRequests.size() == 0 && this.getDelayedRequestsId().size() == 0) { + this.lwM2MTransportService.updatesAndSentModelParameter(this); + } + } + + public ResourceModel.Operations getOperation(String path) { + ResultIds resultIds = new ResultIds(path); + return (this.getModelObjects().get(resultIds.getObjectId()) != null) ? this.getModelObjects().get(resultIds.getObjectId()).getObjectModel().resources.get(resultIds.getResourceId()).operations : ResourceModel.Operations.NONE; + } + + public String getResourceName (String path) { + ResultIds resultIds = new ResultIds(path); + return (this.getModelObjects().get(resultIds.getObjectId()) != null) ? this.getModelObjects().get(resultIds.getObjectId()).getObjectModel().resources.get(resultIds.getResourceId()).name : ""; + } + + /** + * @param path - path resource + * @return - value of Resource or null + */public String getResourceValue(String path) { + String resValue = null; + ResultIds pathIds = new ResultIds(path); + ModelObject modelObject = this.getModelObjects().get(pathIds.getObjectId()); + if (modelObject != null && modelObject.getInstances().get(pathIds.getInstanceId()) != null) { + LwM2mObjectInstance instance = modelObject.getInstances().get(pathIds.getInstanceId()); + if (instance.getResource(pathIds.getResourceId()) != null) { + resValue = instance.getResource(pathIds.getResourceId()).getType() == OPAQUE ? + Hex.encodeHexString((byte[]) instance.getResource(pathIds.getResourceId()).getValue()).toLowerCase() : + (instance.getResource(pathIds.getResourceId()).isMultiInstances()) ? + instance.getResource(pathIds.getResourceId()).getValues().toString() : + instance.getResource(pathIds.getResourceId()).getValue().toString(); + } + } + return resValue; + } } + diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2MSetSecurityStoreServer.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2MSetSecurityStoreServer.java index 7a37ac4005..7e2a9960d1 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2MSetSecurityStoreServer.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2MSetSecurityStoreServer.java @@ -42,10 +42,17 @@ import java.security.GeneralSecurityException; import java.security.KeyStoreException; import java.security.cert.X509Certificate; import java.security.interfaces.ECPublicKey; -import java.security.spec.*; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPoint; +import java.security.spec.ECPrivateKeySpec; +import java.security.spec.ECPublicKeySpec; +import java.security.spec.KeySpec; import java.util.Arrays; -import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.*; +import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.REDIS; +import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.X509; + @Slf4j @Data diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java index 394e7ee5f1..ceea02e55a 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java @@ -26,6 +26,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.DeviceProfile; +import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.transport.lwm2m.secure.LwM2MGetSecurityInfo; import org.thingsboard.server.transport.lwm2m.secure.ReadResultSecurityStore; import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler; @@ -44,7 +45,8 @@ import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.stream.Collectors; -import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.*; +import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.DEFAULT_MODE; +import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.NO_SEC; @Slf4j @Component("LwM2mInMemorySecurityStore") @@ -118,18 +120,22 @@ public class LwM2mInMemorySecurityStore extends InMemorySecurityStore { this.listener = listener; } - public LwM2MClient getlwM2MClient(String endPoint, String identity) { + public LwM2MClient getLwM2MClient(String endPoint, String identity) { Map.Entry modelClients = (endPoint != null) ? this.sessions.entrySet().stream().filter(model -> endPoint.equals(model.getValue().getEndPoint())).findAny().orElse(null) : this.sessions.entrySet().stream().filter(model -> identity.equals(model.getValue().getIdentity())).findAny().orElse(null); return (modelClients != null) ? modelClients.getValue() : null; } - public LwM2MClient getlwM2MClient(String registrationId) { + public LwM2MClient getLwM2MClient(String registrationId) { return this.sessions.get(registrationId); } - public LwM2MClient getlwM2MClient(LeshanServer lwServer, Registration registration) { + public LwM2MClient getLwM2MClient(TransportProtos.SessionInfoProto sessionInfo) { + return this.getSession(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())).entrySet().iterator().next().getValue(); + + } + public LwM2MClient updateInSessionsLwM2MClient(LeshanServer lwServer, Registration registration) { writeLock.lock(); try { if (this.sessions.get(registration.getEndpoint()) == null) { @@ -193,6 +199,10 @@ public class LwM2mInMemorySecurityStore extends InMemorySecurityStore { return this.profiles; } + public AttrTelemetryObserveValue getProfile(UUID profileUuId) { + return this.profiles.get(profileUuId); + } + public MapsetProfiles(Map profiles) { return this.profiles = profiles; } From ca46f5fb7521fde80975d4f20dc95101a30239c0 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Sun, 13 Dec 2020 16:55:48 +0200 Subject: [PATCH 006/249] Lwm2m: backEnd: add DelayedRequest + in the start by to name --- .../transport/DefaultTransportApiService.java | 14 ++-- .../data/security/DeviceCredentialsType.java | 2 - common/queue/src/main/proto/queue.proto | 1 + .../lwm2m/server/LwM2MTransportRequest.java | 69 ++++++++++++++----- .../lwm2m/server/LwM2MTransportService.java | 34 ++++++--- .../lwm2m/server/client/LwM2MClient.java | 2 +- .../transport/adaptor/JsonConverter.java | 3 +- .../device/DeviceCredentialsServiceImpl.java | 9 ++- .../server/dao/device/DeviceServiceImpl.java | 2 + 9 files changed, 94 insertions(+), 42 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java index 0bdeaf360e..76f77c3889 100644 --- a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java +++ b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java @@ -49,34 +49,31 @@ import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; import org.thingsboard.server.dao.device.DeviceCredentialsService; import org.thingsboard.server.dao.device.DeviceProvisionService; import org.thingsboard.server.dao.device.DeviceService; +import org.thingsboard.server.dao.device.provision.ProvisionFailedException; import org.thingsboard.server.dao.device.provision.ProvisionRequest; import org.thingsboard.server.dao.device.provision.ProvisionResponse; import org.thingsboard.server.dao.relation.RelationService; +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.dao.util.mapping.JacksonUtil; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.gen.transport.TransportProtos.DeviceCredentialsProto; import org.thingsboard.server.gen.transport.TransportProtos.DeviceInfoProto; -import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg; -import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayResponseMsg; import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileResponseMsg; +import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg; +import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayResponseMsg; import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceResponseMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceResponseMsgOrBuilder; import org.thingsboard.server.gen.transport.TransportProtos.ProvisionResponseStatus; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceLwM2MCredentialsRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceTokenRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509CertRequestMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceLwM2MCredentialsRequestMsg; import org.thingsboard.server.queue.common.TbProtoQueueMsg; import org.thingsboard.server.queue.util.TbCoreComponent; -import org.thingsboard.server.dao.device.provision.ProvisionFailedException; import org.thingsboard.server.service.apiusage.TbApiUsageStateService; import org.thingsboard.server.service.executors.DbCallbackExecutorService; import org.thingsboard.server.service.profile.TbDeviceProfileCache; -import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.service.queue.TbClusterService; import org.thingsboard.server.service.state.DeviceStateService; @@ -326,6 +323,7 @@ public class DefaultTransportApiService implements TransportApiService { break; case MQTT_BASIC: case X509_CERTIFICATE: + case LWM2M_CREDENTIALS: provisionResponse.setCredentialsValue(deviceCredentials.getCredentialsValue()); break; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/security/DeviceCredentialsType.java b/common/data/src/main/java/org/thingsboard/server/common/data/security/DeviceCredentialsType.java index 84a634a100..6b214ecb38 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/security/DeviceCredentialsType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/security/DeviceCredentialsType.java @@ -21,6 +21,4 @@ public enum DeviceCredentialsType { X509_CERTIFICATE, MQTT_BASIC, LWM2M_CREDENTIALS - - } diff --git a/common/queue/src/main/proto/queue.proto b/common/queue/src/main/proto/queue.proto index 08a0d0ba97..1c2a128eb6 100644 --- a/common/queue/src/main/proto/queue.proto +++ b/common/queue/src/main/proto/queue.proto @@ -77,6 +77,7 @@ enum CredentialsType { ACCESS_TOKEN = 0; X509_CERTIFICATE = 1; MQTT_BASIC = 2; + LWM2M_CREDENTIALS = 3; } message KeyValueProto { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java index 295c3b9f64..40edf09986 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java @@ -23,23 +23,23 @@ import org.eclipse.leshan.core.model.ResourceModel; import org.eclipse.leshan.core.node.LwM2mSingleResource; import org.eclipse.leshan.core.node.ObjectLink; import org.eclipse.leshan.core.observation.Observation; +import org.eclipse.leshan.core.request.CancelObservationRequest; import org.eclipse.leshan.core.request.ContentFormat; -import org.eclipse.leshan.core.request.WriteRequest; import org.eclipse.leshan.core.request.DiscoverRequest; 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.CancelObservationRequest; import org.eclipse.leshan.core.request.ReadRequest; -import org.eclipse.leshan.core.request.ExecuteRequest; import org.eclipse.leshan.core.request.WriteAttributesRequest; -import org.eclipse.leshan.core.response.ResponseCallback; -import org.eclipse.leshan.core.response.LwM2mResponse; -import org.eclipse.leshan.core.response.ObserveResponse; -import org.eclipse.leshan.core.response.ReadResponse; +import org.eclipse.leshan.core.request.WriteRequest; import org.eclipse.leshan.core.response.CancelObservationResponse; import org.eclipse.leshan.core.response.DeleteResponse; -import org.eclipse.leshan.core.response.ExecuteResponse; import org.eclipse.leshan.core.response.DiscoverResponse; +import org.eclipse.leshan.core.response.ExecuteResponse; +import org.eclipse.leshan.core.response.LwM2mResponse; +import org.eclipse.leshan.core.response.ObserveResponse; +import org.eclipse.leshan.core.response.ReadResponse; +import org.eclipse.leshan.core.response.ResponseCallback; import org.eclipse.leshan.core.response.WriteAttributesResponse; import org.eclipse.leshan.core.response.WriteResponse; import org.eclipse.leshan.core.util.Hex; @@ -65,13 +65,13 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandle 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.PUT_TYPE_OPER_WRITE_ATTRIBUTES; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.PUT_TYPE_OPER_WRITE_UPDATE; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.LOG_LW2M_ERROR; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.LOG_LW2M_INFO; 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_OBSERVE_CANCEL; import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.POST_TYPE_OPER_WRITE_REPLACE; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.LOG_LW2M_ERROR; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.LOG_LW2M_INFO; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.PUT_TYPE_OPER_WRITE_ATTRIBUTES; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.PUT_TYPE_OPER_WRITE_UPDATE; @Slf4j @Service("LwM2MTransportRequest") @@ -153,11 +153,11 @@ public class LwM2MTransportRequest { case POST_TYPE_OPER_WRITE_REPLACE: // Request to write a String Single-Instance Resource using the TLV content format. if (contentFormat.equals(ContentFormat.TLV) && !resMultiple) { - request = this.getWriteRequestSingleResource(null, resultIds.getObjectId(), resultIds.getInstanceId(), resultIds.getResourceId(), params, resType); + request = this.getWriteRequestSingleResource(null, resultIds.getObjectId(), resultIds.getInstanceId(), resultIds.getResourceId(), params, resType, registration); } // Mode.REPLACE && Request to write a String Single-Instance Resource using the given content format (TEXT, TLV, JSON) else if (!contentFormat.equals(ContentFormat.TLV) && !resMultiple) { - request = this.getWriteRequestSingleResource(contentFormat, resultIds.getObjectId(), resultIds.getInstanceId(), resultIds.getResourceId(), params, resType); + request = this.getWriteRequestSingleResource(contentFormat, resultIds.getObjectId(), resultIds.getInstanceId(), resultIds.getResourceId(), params, resType, registration); } break; case PUT_TYPE_OPER_WRITE_UPDATE: @@ -212,8 +212,16 @@ public class LwM2MTransportRequest { break; default: } - if (request != null) + if (request != null) { this.sendRequest(lwServer, registration, request, lwM2MClient, timeoutInMs, isDelayedUpdate); + } + else if (request == null && isDelayedUpdate) { + String msg = String.format(LOG_LW2M_ERROR + ": sendRequest: Resource path - %s msg No SendRequest to Client", target); + service.sentLogsToThingsboard(msg, registration.getId()); + log.error("[{}] - [{}] No SendRequest", target); + this.handleResponseError(registration, target, lwM2MClient, isDelayedUpdate); + + } } } @@ -225,6 +233,7 @@ public class LwM2MTransportRequest { * @param lwM2MClient - * @param timeoutInMs - */ + private void sendRequest(LeshanServer lwServer, Registration registration, DownlinkRequest request, LwM2MClient lwM2MClient, long timeoutInMs, boolean isDelayedUpdate) { lwServer.send(registration, request, timeoutInMs, (ResponseCallback) response -> { if (isSuccess(((Response) response.getCoapResponse()).getCode())) { @@ -234,7 +243,6 @@ public class LwM2MTransportRequest { if (isDelayedUpdate) { delayedUpdateStr = " (delayedUpdate) "; } - String msg = String.format(LOG_LW2M_INFO + ": sendRequest Replace%s: CoapCde - %s Lwm2m code - %d name - %s Resource path - %s value - %s SendRequest to Client", delayedUpdateStr, ((Response) response.getCoapResponse()).getCode(), response.getCode().getCode(), response.getCode().getName(), request.getPath().toString(), ((LwM2mSingleResource) ((WriteRequest) request).getNode()).getValue().toString()); @@ -243,20 +251,27 @@ public class LwM2MTransportRequest { ((LwM2mSingleResource) ((WriteRequest) request).getNode()).getValue(), delayedUpdateStr); } } else { - String msg = String.format(LOG_LW2M_ERROR + ": sendRequest: CoapCde - %s Lwm2m code - %d name - %s Resource path - %s SendRequest to Client", + String msg = String.format(LOG_LW2M_ERROR + ": sendRequest: CoapCode - %s Lwm2m code - %d name - %s Resource path - %s SendRequest to Client", ((Response) response.getCoapResponse()).getCode(), response.getCode().getCode(), response.getCode().getName(), request.getPath().toString()); service.sentLogsToThingsboard(msg, registration.getId()); log.error("[{}] - [{}] [{}] error SendRequest", ((Response) response.getCoapResponse()).getCode(), response.getCode(), request.getPath().toString()); + if (request instanceof WriteRequest && ((WriteRequest) request).isReplaceRequest() && isDelayedUpdate) { + this.handleResponseError(registration, request.getPath().toString(), lwM2MClient, isDelayedUpdate); + } } + }, e -> { String msg = String.format(LOG_LW2M_ERROR + ": sendRequest: Resource path - %s msg error - %s SendRequest to Client", request.getPath().toString(), e.toString()); service.sentLogsToThingsboard(msg, registration.getId()); log.error("[{}] - [{}] error SendRequest", request.getPath().toString(), e.toString()); + if (request instanceof WriteRequest && ((WriteRequest) request).isReplaceRequest() && isDelayedUpdate) { + this.handleResponseError(registration, request.getPath().toString(), lwM2MClient, isDelayedUpdate); + } }); } - private WriteRequest getWriteRequestSingleResource(ContentFormat contentFormat, Integer objectId, Integer instanceId, Integer resourceId, Object value, ResourceModel.Type type) { + private WriteRequest getWriteRequestSingleResource(ContentFormat contentFormat, Integer objectId, Integer instanceId, Integer resourceId, Object value, ResourceModel.Type type, Registration registration) { try { switch (type) { case STRING: // String @@ -270,7 +285,7 @@ public class LwM2MTransportRequest { case FLOAT: // Double return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, Double.valueOf(value.toString())) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, Double.valueOf(value.toString())); case TIME: // Date - return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, new Date((Long) Integer.toUnsignedLong(Integer.valueOf(value.toString())))) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, new Date((Long) Integer.toUnsignedLong(Integer.valueOf(value.toString())))); + return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, new Date(Long.decode(value.toString()))) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, new Date((Long) Integer.toUnsignedLong(Integer.valueOf(value.toString())))); case OPAQUE: // byte[] value, base64 return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, Hex.decodeHex(value.toString().toCharArray())) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, Hex.decodeHex(value.toString().toCharArray())); default: @@ -278,6 +293,9 @@ public class LwM2MTransportRequest { return null; } catch (NumberFormatException e) { String patn = "/" + objectId + "/" + instanceId + "/" + resourceId; + String msg = String.format(LOG_LW2M_ERROR + ": NumberFormatException: Resource path - %s type - %s value - %s msg error - %s SendRequest to Client", + patn, type, value, e.toString()); + service.sentLogsToThingsboard(msg, registration.getId()); log.error("Path: [{}] type: [{}] value: [{}] errorMsg: [{}]]", patn, type, value, e.toString()); return null; } @@ -296,6 +314,19 @@ public class LwM2MTransportRequest { }); } + private void handleResponseError(Registration registration, final String path, LwM2MClient lwM2MClient, boolean isDelayedUpdate) { + executorService.submit(new Runnable() { + @Override + public void run() { + try { + if (isDelayedUpdate) lwM2MClient.onSuccessOrErrorDelayedRequests(path); + } catch (RuntimeException t) { + log.error("[{}] endpoint [{}] path [{}] error Unable to after send response.", registration.getEndpoint(), path, t.toString()); + } + } + }); + } + /** * processing a response from a client * @param registration - diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java index b37d419987..06cf04a88a 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java @@ -77,6 +77,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Predicate; import java.util.stream.Collectors; +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.DEFAULT_TIMEOUT; import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.DEVICE_ATTRIBUTES_REQUEST; @@ -330,7 +331,7 @@ public class LwM2MTransportService { } // #2.2 else { - lwM2MClient.onSuccessDelayedRequests(null); + lwM2MClient.onSuccessOrErrorDelayedRequests(null); } } } @@ -361,11 +362,15 @@ public class LwM2MTransportService { }); // #2.1 lwM2MClient.getDelayedRequests().forEach((k, v)->{ - this.putDelayedUpdateResourcesClient (lwM2MClient, lwM2MClient.getResourceValue(k), v.getKv().getStringV(), k); + List listV = new ArrayList(); + listV.add(v.getKv()); + this.putDelayedUpdateResourcesClient (lwM2MClient, lwM2MClient.getResourceValue(k), getJsonObject(listV).get(v.getKv().getKey()), k); System.out.printf(" k: %s, v: %s%n, v1: %s%n", k, v.getKv().getStringV(), lwM2MClient.getResourceValue(k)); }); lwM2MClient.getDelayedRequestsId().remove(attributesResponse.getRequestId()); -// lwM2MClient.onSuccessDelayedRequests(); + if (lwM2MClient.getDelayedRequests().size() == 0) { + lwM2MClient.onSuccessOrErrorDelayedRequests(null); + } } } @@ -686,7 +691,7 @@ public class LwM2MTransportService { String value = de.getValue().getAsString(); LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getSession(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())).entrySet().iterator().next().getValue(); AttrTelemetryObserveValue profile = lwM2mInMemorySecurityStore.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); - if (path != null && validatePathInAttrProfile(profile.getPostAttributeProfile(), path)) { + if (path != null && (this.validatePathInAttrProfile(profile, path) || this.validatePathInTelemetryProfile(profile, path))) { if (lwM2MClient.getOperation(path).isWritable()) { lwM2MTransportRequest.sendAllRequest(lwM2MClient.getLwServer(), lwM2MClient.getRegistration(), path, POST_TYPE_OPER_WRITE_REPLACE, ContentFormat.TLV.getName(), lwM2MClient, null, value, this.context.getCtxServer().getTimeout(), @@ -714,7 +719,7 @@ public class LwM2MTransportService { * * @param sessionInfo - * @param name - - * @return + * @return true if path isPresent in postProfile */ private String getPathAttributeUpdate(TransportProtos.SessionInfoProto sessionInfo, String name) { String profilePath = this.getPathAttributeUpdateProfile(sessionInfo, name); @@ -722,15 +727,25 @@ public class LwM2MTransportService { } /** - * @param postAttributeProfile - + * @param profile - * @param path - * @return true if path isPresent in postAttributeProfile */ - private boolean validatePathInAttrProfile(JsonArray postAttributeProfile, String path) { - Set attributesSet = new Gson().fromJson(postAttributeProfile, Set.class); + private boolean validatePathInAttrProfile(AttrTelemetryObserveValue profile, String path) { + Set attributesSet = new Gson().fromJson(profile.getPostAttributeProfile(), Set.class); return attributesSet.stream().filter(p -> p.equals(path)).findFirst().isPresent(); } + /** + * @param profile - + * @param path - + * @return true if path isPresent in postAttributeProfile + */ + private boolean validatePathInTelemetryProfile(AttrTelemetryObserveValue profile, String path) { + Set telemetriesSet = new Gson().fromJson(profile.getPostTelemetryProfile(), Set.class); + return telemetriesSet.stream().filter(p -> p.equals(path)).findFirst().isPresent(); + } + /** * Get path to resource from profile equal keyName @@ -786,8 +801,7 @@ public class LwM2MTransportService { } else { this.onObservationSetResourcesValue(registration, ((LwM2mSingleResource) request.getNode()).getValue(), null, path); } - - if (isDelayedUpdate) lwM2MClient.onSuccessDelayedRequests (request.getPath().toString()); + if (isDelayedUpdate) lwM2MClient.onSuccessOrErrorDelayedRequests(request.getPath().toString()); } /** diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java index a28d7257d5..5fd63fa53f 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java @@ -114,7 +114,7 @@ public class LwM2MClient implements Cloneable { }); } - public void onSuccessDelayedRequests (String path) { + public void onSuccessOrErrorDelayedRequests(String path) { if (path != null) this.delayedRequests.remove(path); if (this.delayedRequests.size() == 0 && this.getDelayedRequestsId().size() == 0) { this.lwM2MTransportService.updatesAndSentModelParameter(this); diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/adaptor/JsonConverter.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/adaptor/JsonConverter.java index a20f697bba..d745ebeb65 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/adaptor/JsonConverter.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/adaptor/JsonConverter.java @@ -59,7 +59,6 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TreeMap; -import java.util.UUID; import java.util.function.Consumer; import java.util.stream.Collectors; @@ -426,6 +425,8 @@ public class JsonConverter { case MQTT_BASIC: result.add("credentialsValue", JSON_PARSER.parse(payload.getCredentialsValue()).getAsJsonObject()); break; + case LWM2M_CREDENTIALS: + break; } result.addProperty("credentialsType", payload.getCredentialsType().name()); result.addProperty("status", ProvisionResponseStatus.SUCCESS.name()); diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java index ff1763f662..db123746ab 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java @@ -21,7 +21,6 @@ import org.hibernate.exception.ConstraintViolationException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import org.thingsboard.server.common.data.Device; @@ -87,6 +86,9 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen case MQTT_BASIC: formatSimpleMqttCredentials(deviceCredentials); break; + case LWM2M_CREDENTIALS: + formatSimpleLwm2mCredentials(deviceCredentials); + break; } log.trace("Executing updateDeviceCredentials [{}]", deviceCredentials); credentialsValidator.validate(deviceCredentials, id -> tenantId); @@ -129,6 +131,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen deviceCredentials.setCredentialsValue(JacksonUtil.toString(mqttCredentials)); } + private void formatCertData(DeviceCredentials deviceCredentials) { String cert = EncryptionUtil.trimNewLines(deviceCredentials.getCredentialsValue()); String sha3Hash = EncryptionUtil.getSha3Hash(cert); @@ -136,6 +139,10 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen deviceCredentials.setCredentialsValue(cert); } + private void formatSimpleLwm2mCredentials(DeviceCredentials deviceCredentials) { + + } + @Override @CacheEvict(cacheNames = DEVICE_CREDENTIALS_CACHE, key = "'deviceCredentials_' + #deviceCredentials.credentialsId") public void deleteDeviceCredentials(TenantId tenantId, DeviceCredentials deviceCredentials) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index a919f86dfe..9024ed0ee2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -512,6 +512,8 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe case X509_CERTIFICATE: deviceCredentials.setCredentialsValue(provisionRequest.getCredentialsData().getX509CertHash()); break; + case LWM2M_CREDENTIALS: + break; } try { deviceCredentialsService.updateDeviceCredentials(savedDevice.getTenantId(), deviceCredentials); From 1150d4e4f30180ae2c54e3bdca5f36e525c2772a Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 22 Dec 2020 16:23:03 +0200 Subject: [PATCH 007/249] Lwm2m: backEnd: add saveDeviceWithCredential --- .../server/controller/DeviceController.java | 1 - .../controller/DeviceLwm2mController.java | 53 +++++- .../server/dao/device/DeviceService.java | 3 + .../server/common/data/Device.java | 12 +- .../lwm2m/server/LwM2MTransportHandler.java | 65 +++---- .../lwm2m/server/LwM2MTransportRequest.java | 34 ++-- .../lwm2m/server/LwM2MTransportService.java | 171 +++++++++++------- .../lwm2m/server/LwM2mServerListener.java | 11 +- .../lwm2m/server/client/LwM2MClient.java | 54 +++--- .../lwm2m/server/client/ModelObject.java | 6 +- .../server/dao/device/DeviceServiceImpl.java | 45 +++-- .../thingsboard/rest/client/RestClient.java | 19 ++ 12 files changed, 313 insertions(+), 161 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java index e2db45884f..68a016bf4e 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -278,7 +278,6 @@ public class DeviceController extends BaseController { try { Device device = checkDeviceId(deviceCredentials.getDeviceId(), Operation.WRITE_CREDENTIALS); DeviceCredentials result = checkNotNull(deviceCredentialsService.updateDeviceCredentials(getCurrentUser().getTenantId(), deviceCredentials)); - //log.info("0 LwM2M CredentialsUpdate start) tbClusterService.pushMsgToCore(new DeviceCredentialsUpdateNotificationMsg(getCurrentUser().getTenantId(), deviceCredentials.getDeviceId(), result), null); logEntityAction(device.getId(), device, device.getCustomerId(), diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceLwm2mController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceLwm2mController.java index 76915fbed1..c38a163af9 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceLwm2mController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceLwm2mController.java @@ -15,17 +15,32 @@ */ package org.thingsboard.server.controller; +import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; +import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg; +import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.lwm2m.LwM2mObject; import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; +import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.security.permission.Resource; import java.util.List; +import java.util.Map; @Slf4j @RestController @@ -72,4 +87,40 @@ public class DeviceLwm2mController extends BaseController { throw handleException(e); } } + + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") + @RequestMapping(value = "/lwm2m/device-credentials", method = RequestMethod.POST) + @ResponseBody + public Device saveDeviceWithCredentials(@RequestBody (required=false) Map, Object> deviceWithDeviceCredentials) throws ThingsboardException { + ObjectMapper mapper = new ObjectMapper(); + Device device = checkNotNull(mapper.convertValue(deviceWithDeviceCredentials.get(Device.class), Device.class)); + DeviceCredentials credentials = checkNotNull(mapper.convertValue( deviceWithDeviceCredentials.get(DeviceCredentials.class), DeviceCredentials.class)); + try { + device.setTenantId(getCurrentUser().getTenantId()); + checkEntity(device.getId(), device, Resource.DEVICE); + Device savedDevice = deviceService.saveDeviceWithCredentials(device, credentials); + checkNotNull(savedDevice); + + tbClusterService.onDeviceChange(savedDevice, null); + tbClusterService.pushMsgToCore(new DeviceNameOrTypeUpdateMsg(savedDevice.getTenantId(), + savedDevice.getId(), savedDevice.getName(), savedDevice.getType()), null); + tbClusterService.onEntityStateChange(savedDevice.getTenantId(), savedDevice.getId(), + device.getId() == null ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); + + logEntityAction(savedDevice.getId(), savedDevice, + savedDevice.getCustomerId(), + device.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); + + if (device.getId() == null) { + deviceStateService.onDeviceAdded(savedDevice); + } else { + deviceStateService.onDeviceUpdated(savedDevice); + } + return savedDevice; + } catch (Exception e) { + logEntityAction(emptyId(EntityType.DEVICE), device, + null, device.getId() == null ? ActionType.ADDED : ActionType.UPDATED, e); + throw handleException(e); + } + } } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java index 715313538d..a54bb7af7e 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java @@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.dao.device.provision.ProvisionRequest; import java.util.List; @@ -45,6 +46,8 @@ public interface DeviceService { Device saveDeviceWithAccessToken(Device device, String accessToken); + Device saveDeviceWithCredentials(Device device, DeviceCredentials deviceCredentials); + Device assignDeviceToCustomer(TenantId tenantId, DeviceId deviceId, CustomerId customerId); Device unassignDeviceFromCustomer(TenantId tenantId, DeviceId deviceId); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/Device.java b/common/data/src/main/java/org/thingsboard/server/common/data/Device.java index ca8e5f5575..64c608ecb8 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/Device.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/Device.java @@ -20,7 +20,6 @@ import com.fasterxml.jackson.core.JsonProcessingException; import lombok.EqualsAndHashCode; import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.common.data.device.data.DeviceData; -import org.thingsboard.server.common.data.device.profile.DeviceProfileData; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceProfileId; @@ -64,6 +63,17 @@ public class Device extends SearchTextBasedWithAdditionalInfo implemen this.setDeviceData(device.getDeviceData()); } + public Device updateDevice(Device device) { + this.tenantId = device.getTenantId(); + this.customerId = device.getCustomerId(); + this.name = device.getName(); + this.type = device.getType(); + this.label = device.getLabel(); + this.deviceProfileId = device.getDeviceProfileId(); + this.setDeviceData(device.getDeviceData()); + return this; + } + public TenantId getTenantId() { return tenantId; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportHandler.java index 814cac6d9f..d37b429101 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportHandler.java @@ -45,15 +45,9 @@ import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import javax.annotation.PostConstruct; import java.io.File; import java.io.IOException; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.Date; import java.util.LinkedList; -import java.util.List; -import java.util.Map; import java.util.Optional; @Slf4j @@ -127,14 +121,19 @@ public class LwM2MTransportHandler{ @PostConstruct public void init() { - LwM2mServerListener lwM2mServerListener = new LwM2mServerListener(lhServerCert, service); - this.lhServerCert.getRegistrationService().addListener(lwM2mServerListener.registrationListener); - this.lhServerCert.getPresenceService().addListener(lwM2mServerListener.presenceListener); - this.lhServerCert.getObservationService().addListener(lwM2mServerListener.observationListener); - lwM2mServerListener = new LwM2mServerListener(lhServerNoSecPskRpk, service); - this.lhServerNoSecPskRpk.getRegistrationService().addListener(lwM2mServerListener.registrationListener); - this.lhServerNoSecPskRpk.getPresenceService().addListener(lwM2mServerListener.presenceListener); - this.lhServerNoSecPskRpk.getObservationService().addListener(lwM2mServerListener.observationListener); + try { + LwM2mServerListener lwM2mServerListener = new LwM2mServerListener(lhServerCert, service); + this.lhServerCert.getRegistrationService().addListener(lwM2mServerListener.registrationListener); + this.lhServerCert.getPresenceService().addListener(lwM2mServerListener.presenceListener); + this.lhServerCert.getObservationService().addListener(lwM2mServerListener.observationListener); + lwM2mServerListener = new LwM2mServerListener(lhServerNoSecPskRpk, service); + this.lhServerNoSecPskRpk.getRegistrationService().addListener(lwM2mServerListener.registrationListener); + this.lhServerNoSecPskRpk.getPresenceService().addListener(lwM2mServerListener.presenceListener); + this.lhServerNoSecPskRpk.getObservationService().addListener(lwM2mServerListener.observationListener); + } + catch (java.lang.NullPointerException e) { + log.error("init [{}]", e.toString()); + } } public static NetworkConfig getCoapConfig() { @@ -150,7 +149,8 @@ public class LwM2MTransportHandler{ return coapConfig; } - public static String getValueTypeToString (Object value, ResourceModel.Type type) { + public static String getValueTypeToString (Object value, ResourceModel.Type type, int val) { + try{ switch (type) { case STRING: // String case OBJLNK: // ObjectLink @@ -160,16 +160,21 @@ public class LwM2MTransportHandler{ case BOOLEAN: // Boolean return Boolean.toString((Boolean) value); case FLOAT: // Double - return Double.toString((Float)value); + return Double.toString((Double) value); case TIME: // Date - String DATE_FORMAT = "MMM d, yyyy HH:mm a"; - DateFormat formatter = new SimpleDateFormat(DATE_FORMAT); - return formatter.format(new Date(Integer.toUnsignedLong((Integer) value))); + return Long.toString(((Date) value).getTime()); +// String DATE_FORMAT = "MMM d, yyyy HH:mm a"; +// DateFormat formatter = new SimpleDateFormat(DATE_FORMAT); +// return formatter.format(new Date(Integer.toUnsignedLong((Integer) value))); case OPAQUE: // byte[] value, base64 return Hex.encodeHexString((byte[])value); default: return null; } + } catch (Exception e) { + log.error(e.getStackTrace().toString()); + return null; + } } public static LwM2mNode getLvM2mNodeToObject(LwM2mNode content) { @@ -305,28 +310,6 @@ public class LwM2MTransportHandler{ } } - /** - * Equals to Map for values - * @param map1 - - * @param map2 - - * @param - - * @return - true if equals - */ - public static > boolean mapsEquals(Map map1, Map map2) { - List values1 = new ArrayList<>(map1.values()); - List values2 = new ArrayList<>(map2.values()); - Collections.sort(values1); - Collections.sort(values2); - return values1.equals(values2); - } - - public static String convertCamelCase (String str) { - str = str.toLowerCase().replace("/[^a-z ]+/g", " "); - str = str.replace("/^(.)|\\s(.)/g", "$1"); - str = str.replace("/[^a-zA-Z]+/g", ""); - return str; - } - public static String splitCamelCaseString(String s){ LinkedList linkedListOut = new LinkedList<>(); LinkedList linkedList = new LinkedList((Arrays.asList(s.split(" ")))); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java index 40edf09986..576415da31 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java @@ -20,6 +20,7 @@ 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.LwM2mPath; import org.eclipse.leshan.core.node.LwM2mSingleResource; import org.eclipse.leshan.core.node.ObjectLink; import org.eclipse.leshan.core.observation.Observation; @@ -50,6 +51,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Service; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import javax.annotation.PostConstruct; import java.util.ArrayList; @@ -79,16 +81,17 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandle public class LwM2MTransportRequest { private final ExecutorService executorService; private static final String RESPONSE_CHANNEL = "THINGSBOARD_RESP"; + private final LwM2mValueConverterImpl converter; @Autowired LwM2MTransportService service; public LwM2MTransportRequest() { + this.converter = new LwM2mValueConverterImpl(); executorService = Executors.newCachedThreadPool( new NamedThreadFactory(String.format("LwM2M %s channel response", RESPONSE_CHANNEL))); } - @PostConstruct public void init() { } @@ -115,12 +118,12 @@ public class LwM2MTransportRequest { */ public void sendAllRequest(LeshanServer lwServer, Registration registration, String target, String typeOper, String contentFormatParam, LwM2MClient lwM2MClient, Observation observation, Object params, long timeoutInMs, boolean isDelayedUpdate) { - ResultIds resultIds = new ResultIds(target); + LwM2mPath resultIds = new LwM2mPath(target); if (registration != null && resultIds.getObjectId() >= 0) { DownlinkRequest request = null; ContentFormat contentFormat = contentFormatParam != null ? ContentFormat.fromName(contentFormatParam.toUpperCase()) : null; - ResourceModel resource = (resultIds.resourceId >= 0) ? (lwM2MClient != null) ? - lwM2MClient.getModelObjects().get(resultIds.getObjectId()).getObjectModel().resources.get(resultIds.resourceId) : null : null; + ResourceModel resource = (resultIds.getResourceId() !=null && lwM2MClient != null) ? + lwM2MClient.getModelObjects().get(resultIds.getObjectId()).getObjectModel().resources.get(resultIds.getResourceId()) : null; ResourceModel.Type resType = (resource == null) ? null : resource.type; boolean resMultiple = (resource == null) ? false : resource.multiple; timeoutInMs = timeoutInMs > 0 ? timeoutInMs : DEFAULT_TIMEOUT; @@ -132,10 +135,10 @@ public class LwM2MTransportRequest { request = new DiscoverRequest(target); break; case GET_TYPE_OPER_OBSERVE: - if (resultIds.getResourceId() >= 0) { - request = new ObserveRequest(resultIds.getObjectId(), resultIds.getInstanceId(), resultIds.getResourceId()); - } else if (resultIds.getInstanceId() >= 0) { - request = new ObserveRequest(resultIds.getObjectId(), resultIds.getInstanceId()); + if (resultIds.isResource()) { + request = new ObserveRequest(resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId()); + } else if (resultIds.isObjectInstance()) { + request = new ObserveRequest(resultIds.getObjectId(), resultIds.getObjectInstanceId()); } else if (resultIds.getObjectId() >= 0) { request = new ObserveRequest(resultIds.getObjectId()); } @@ -145,7 +148,8 @@ public class LwM2MTransportRequest { break; case POST_TYPE_OPER_EXECUTE: if (params != null && !resMultiple) { - request = new ExecuteRequest(target, LwM2MTransportHandler.getValueTypeToString(params, resType)); +// request = new ExecuteRequest(target, LwM2MTransportHandler.getValueTypeToString(params, resType)); + request = new ExecuteRequest(target, (String) this.converter.convertValue(params, resType, ResourceModel.Type.STRING, resultIds)); } else { request = new ExecuteRequest(target); } @@ -153,11 +157,11 @@ public class LwM2MTransportRequest { case POST_TYPE_OPER_WRITE_REPLACE: // Request to write a String Single-Instance Resource using the TLV content format. if (contentFormat.equals(ContentFormat.TLV) && !resMultiple) { - request = this.getWriteRequestSingleResource(null, resultIds.getObjectId(), resultIds.getInstanceId(), resultIds.getResourceId(), params, resType, registration); + request = this.getWriteRequestSingleResource(null, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), params, resType, registration); } // Mode.REPLACE && Request to write a String Single-Instance Resource using the given content format (TEXT, TLV, JSON) else if (!contentFormat.equals(ContentFormat.TLV) && !resMultiple) { - request = this.getWriteRequestSingleResource(contentFormat, resultIds.getObjectId(), resultIds.getInstanceId(), resultIds.getResourceId(), params, resType, registration); + request = this.getWriteRequestSingleResource(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), params, resType, registration); } break; case PUT_TYPE_OPER_WRITE_UPDATE: @@ -202,10 +206,10 @@ public class LwM2MTransportRequest { Attribute pmin = new Attribute(MINIMUM_PERIOD, Integer.toUnsignedLong(Integer.valueOf("1"))); Attribute[] attrs = {pmin}; AttributeSet attrSet = new AttributeSet(attrs); - if (resultIds.getResourceId() >= 0) { - request = new WriteAttributesRequest(resultIds.getObjectId(), resultIds.getInstanceId(), resultIds.getResourceId(), attrSet); - } else if (resultIds.getInstanceId() >= 0) { - request = new WriteAttributesRequest(resultIds.getObjectId(), resultIds.getInstanceId(), attrSet); + 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); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java index 06cf04a88a..861afa02a8 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java @@ -64,7 +64,6 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; -import java.util.Objects; import java.util.Optional; import java.util.Random; import java.util.Set; @@ -186,9 +185,9 @@ public class LwM2MTransportService { if (lwM2mInMemorySecurityStore.getProfiles().size() > 0) { this.syncSessionsAndProfiles(); } - log.info("Client: [{}] unReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType()); + log.info("Client close session: [{}] unReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType()); } else { - log.error("Client: [{}] unReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); + log.error("Client close session: [{}] unReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); } } @@ -242,15 +241,15 @@ public class LwM2MTransportService { private void setLwM2MClient(LeshanServer lwServer, Registration registration, LwM2MClient lwM2MClient) { // #1 Arrays.stream(registration.getObjectLinks()).forEach(url -> { - ResultIds pathIds = new ResultIds(url.getUrl()); - if (pathIds.instanceId > -1 && pathIds.resourceId == -1) { + LwM2mPath pathIds = new LwM2mPath(url.getUrl()); + if (pathIds.isObjectInstance() && !pathIds.isResource()) { lwM2MClient.getPendingRequests().add(url.getUrl()); } }); // #2 Arrays.stream(registration.getObjectLinks()).forEach(url -> { - ResultIds pathIds = new ResultIds(url.getUrl()); - if (pathIds.instanceId > -1 && pathIds.resourceId == -1) { + LwM2mPath pathIds = new LwM2mPath(url.getUrl()); + if (pathIds.isObjectInstance() && !pathIds.isResource()) { lwM2MTransportRequest.sendAllRequest(lwServer, registration, url.getUrl(), GET_TYPE_OPER_READ, ContentFormat.TLV.getName(), lwM2MClient, null, null, this.context.getCtxServer().getTimeout(), false); } @@ -361,10 +360,10 @@ public class LwM2MTransportService { } }); // #2.1 - lwM2MClient.getDelayedRequests().forEach((k, v)->{ + lwM2MClient.getDelayedRequests().forEach((k, v) -> { List listV = new ArrayList(); listV.add(v.getKv()); - this.putDelayedUpdateResourcesClient (lwM2MClient, lwM2MClient.getResourceValue(k), getJsonObject(listV).get(v.getKv().getKey()), k); + this.putDelayedUpdateResourcesClient(lwM2MClient, lwM2MClient.getResourceValue(k), getJsonObject(listV).get(v.getKv().getKey()), k); System.out.printf(" k: %s, v: %s%n, v1: %s%n", k, v.getKv().getStringV(), lwM2MClient.getResourceValue(k)); }); lwM2MClient.getDelayedRequestsId().remove(attributesResponse.getRequestId()); @@ -374,7 +373,7 @@ public class LwM2MTransportService { } } - private void putDelayedUpdateResourcesClient (LwM2MClient lwM2MClient, Object valueOld, Object valueNew, String path){ + private void putDelayedUpdateResourcesClient(LwM2MClient lwM2MClient, Object valueOld, Object valueNew, String path) { if (!valueOld.toString().equals(valueNew.toString())) { lwM2MTransportRequest.sendAllRequest(lwM2MClient.getLwServer(), lwM2MClient.getRegistration(), path, POST_TYPE_OPER_WRITE_REPLACE, ContentFormat.TLV.getName(), lwM2MClient, null, valueNew, this.context.getCtxServer().getTimeout(), @@ -465,18 +464,20 @@ public class LwM2MTransportService { private void getParametersFromProfile(JsonObject attributes, JsonObject telemetry, Registration registration, Set path) { AttrTelemetryObserveValue attrTelemetryObserveValue = lwM2mInMemorySecurityStore.getProfiles().get(lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getProfileUuid()); attrTelemetryObserveValue.getPostAttributeProfile().forEach(p -> { - ResultIds pathIds = new ResultIds(p.getAsString().toString()); - if (pathIds.getResourceId() > -1) { +// ResultIds pathIds = new ResultIds(p.getAsString().toString()); + LwM2mPath pathIds = new LwM2mPath(p.getAsString().toString()); + if (pathIds.isResource()) { if (path == null || path.contains(p.getAsString())) { - this.addParameters(p.getAsString().toString(), attributes, registration); + this.addParameters(p.getAsString().toString(), attributes, registration, "attributes"); } } }); attrTelemetryObserveValue.getPostTelemetryProfile().forEach(p -> { - ResultIds pathIds = new ResultIds(p.getAsString().toString()); - if (pathIds.getResourceId() > -1) { +// ResultIds pathIds = new ResultIds(p.getAsString().toString()); + LwM2mPath pathIds = new LwM2mPath(p.getAsString().toString()); + if (pathIds.isResource()) { if (path == null || path.contains(p.getAsString())) { - this.addParameters(p.getAsString().toString(), telemetry, registration); + this.addParameters(p.getAsString().toString(), telemetry, registration, "telemetry"); } } }); @@ -486,13 +487,19 @@ public class LwM2MTransportService { * @param parameters - JsonObject attributes/telemetry * @param registration - Registration LwM2M Client */ - private void addParameters(String path, JsonObject parameters, Registration registration) { + private void addParameters(String path, JsonObject parameters, Registration registration, String nameParam) { JsonObject names = lwM2mInMemorySecurityStore.getProfiles().get(lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getProfileUuid()).getPostKeyNameProfile(); String resName = String.valueOf(names.get(path)); if (resName != null && !resName.isEmpty()) { - String resValue = lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getResourceValue(path); - if (resValue != null) { - parameters.addProperty(resName, resValue); + String resValue = null; + try { + resValue = lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getResourceValue(path); + if (resValue != null) { +// log.info("addParameters Path: [{}] ResValue : [{}] nameParam [{}]", path, lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getResourceValue(path), nameParam); + parameters.addProperty(resName, resValue); + } + } catch (Exception e) { + log.error(e.getStackTrace().toString()); } } } @@ -629,42 +636,73 @@ public class LwM2MTransportService { * @param path - resource */ private void onObservationSetResourcesValue(Registration registration, Object value, Map values, String path) { - ResultIds resultIds = new ResultIds(path); - // #1 - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(registration.getId()); - ModelObject modelObject = lwM2MClient.getModelObjects().get(resultIds.getObjectId()); - Map instancesModelObject = modelObject.getInstances(); - LwM2mObjectInstance instanceOld = (instancesModelObject.get(resultIds.instanceId) != null) ? instancesModelObject.get(resultIds.instanceId) : null; - Map resourcesOld = (instanceOld != null) ? instanceOld.getResources() : null; - LwM2mResource resourceOld = (resourcesOld != null && resourcesOld.get(resultIds.getResourceId()) != null) ? resourcesOld.get(resultIds.getResourceId()) : null; - // #2 - LwM2mResource resourceNew; - if (Objects.requireNonNull(resourceOld).isMultiInstances()) { - resourceNew = LwM2mMultipleResource.newResource(resultIds.getResourceId(), values, resourceOld.getType()); - } else { - resourceNew = LwM2mSingleResource.newResource(resultIds.getResourceId(), value, resourceOld.getType()); - } - //#3 - Map resourcesNew = new HashMap<>(resourcesOld); - // #4 - resourcesNew.remove(resourceOld); - // #5 - resourcesNew.put(resultIds.getResourceId(), resourceNew); - // #6 - LwM2mObjectInstance instanceNew = new LwM2mObjectInstance(resultIds.instanceId, resourcesNew.values()); - // #7 - CountDownLatch respLatch = new CountDownLatch(1); - lwM2MClient.getModelObjects().get(resultIds.getObjectId()).removeInstance(resultIds.instanceId); - instancesModelObject.put(resultIds.instanceId, instanceNew); - respLatch.countDown(); try { - respLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); - } catch (InterruptedException ex) { - ex.printStackTrace(); + CountDownLatch respLatch = new CountDownLatch(1); + try { + // #1 + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(registration.getId()); + LwM2mPath resultIds = new LwM2mPath(path); + log.warn("#0 nameDevice: [{}] resultIds: [{}] value: [{}], values: [{}] ", lwM2MClient.getDeviceName(), resultIds, value, values); + ResourceModel.Type resType = lwM2MClient.getModelObjects().get(resultIds.getObjectId()).getObjectModel().resources.get(resultIds.getResourceId()).type; + Map instancesModelObject = (lwM2MClient.getModelObjects().get(resultIds.getObjectId()) != null) ? lwM2MClient.getModelObjects().get(resultIds.getObjectId()).getInstances() : null; + Map resourcesOld = null; + try { + CountDownLatch respResLatch = new CountDownLatch(1); + try { + resourcesOld = (instancesModelObject != null && + instancesModelObject.get(resultIds.getObjectInstanceId()) != null && + instancesModelObject.get(resultIds.getObjectInstanceId()).getResources() != null) ? instancesModelObject.get(resultIds.getObjectInstanceId()).getResources() : null; + + } finally { + respResLatch.countDown(); + } + try { + respResLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); + } catch (InterruptedException ex) { + ex.printStackTrace(); + log.error("#1_2 Update ResourcesValue after Observation in CountDownLatch is unsuccessfully path: [{}] value: [{}]", path, value); + } + } catch (Exception e) { + e.printStackTrace(); + log.error("#1_2_1 Update ResourcesValue after Observation in CountDownLatch is unsuccessfully path: [{}] value: [{}]", path, value); + } + LwM2mResource resourceOld = (resourcesOld != null && resourcesOld.get(resultIds.getResourceId()) != null) ? resourcesOld.get(resultIds.getResourceId()) : null; + // #2 + LwM2mResource resourceNew = null; + if ((resourceOld != null && resourceOld.isMultiInstances() && !resourceOld.getValues().equals(values)) || + (resourceOld == null && value == null)) { + resourceNew = LwM2mMultipleResource.newResource(resultIds.getResourceId(), values, resType); + } else if ((resourceOld != null && !resourceOld.isMultiInstances() && !resourceOld.getValue().equals(values)) || + (resourceOld == null && value != null)) { + resourceNew = LwM2mSingleResource.newResource(resultIds.getResourceId(), value, resType); + } + if (resourceNew != null) { + //#3 + Map resourcesNew = (resourcesOld == null) ? new HashMap<>() : new HashMap<>(resourcesOld); + // #4 + if ((resourceOld != null)) resourcesNew.remove(resourceOld); + // #5 + resourcesNew.put(resultIds.getResourceId(), resourceNew); + // #6 + LwM2mObjectInstance instanceNew = new LwM2mObjectInstance(resultIds.getObjectInstanceId(), resourcesNew.values()); + // #7 + lwM2MClient.getModelObjects().get(resultIds.getObjectId()).removeInstance(resultIds.getObjectInstanceId()); + instancesModelObject.put(resultIds.getObjectInstanceId(), instanceNew); + Set paths = new HashSet<>(); + paths.add(path); + this.updateAttrTelemetry(registration, false, paths); + } + } finally { + respLatch.countDown(); + } + try { + respLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); + } catch (InterruptedException ex) { + ex.printStackTrace(); + log.error("#1_1 Update ResourcesValue after Observation in CountDownLatch is unsuccessfully path: [{}] value: [{}]", path, value); + } + } catch (Exception ignored) { } - Set paths = new HashSet<>(); - paths.add(path); - this.updateAttrTelemetry(registration, false, paths); } /** @@ -696,7 +734,7 @@ public class LwM2MTransportService { lwM2MTransportRequest.sendAllRequest(lwM2MClient.getLwServer(), lwM2MClient.getRegistration(), path, POST_TYPE_OPER_WRITE_REPLACE, ContentFormat.TLV.getName(), lwM2MClient, null, value, this.context.getCtxServer().getTimeout(), false); - log.info("[{}] path onAttributeUpdate", path); +// log.info("[{}] path onAttributeUpdate", path); } else { log.error(LOG_LW2M_ERROR + ": Resource path - [{}] value - [{}] is not Writable and cannot be updated", path, value); String logMsg = String.format(LOG_LW2M_ERROR + ": attributeUpdate: Resource path - %s value - %s is not Writable and cannot be updated", path, value); @@ -728,7 +766,7 @@ public class LwM2MTransportService { /** * @param profile - - * @param path - + * @param path - * @return true if path isPresent in postAttributeProfile */ private boolean validatePathInAttrProfile(AttrTelemetryObserveValue profile, String path) { @@ -738,7 +776,7 @@ public class LwM2MTransportService { /** * @param profile - - * @param path - + * @param path - * @return true if path isPresent in postAttributeProfile */ private boolean validatePathInTelemetryProfile(AttrTelemetryObserveValue profile, String path) { @@ -793,9 +831,10 @@ public class LwM2MTransportService { * @param request - */ public void onAttributeUpdateOk(Registration registration, String path, WriteRequest request, boolean isDelayedUpdate) { - ResultIds resultIds = new ResultIds(path); +// ResultIds resultIds = new ResultIds(path); + LwM2mPath resultIds = new LwM2mPath(path); LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(registration.getId()); - LwM2mResource resource = lwM2MClient.getModelObjects().get(resultIds.getObjectId()).getInstances().get(resultIds.getInstanceId()).getResource(resultIds.getResourceId()); + LwM2mResource resource = lwM2MClient.getModelObjects().get(resultIds.getObjectId()).getInstances().get(resultIds.getObjectInstanceId()).getResource(resultIds.getResourceId()); if (resource.isMultiInstances()) { this.onObservationSetResourcesValue(registration, null, ((LwM2mSingleResource) request.getNode()).getValues(), path); } else { @@ -996,9 +1035,10 @@ public class LwM2MTransportService { */ private void updateResourceValueObserve(LeshanServer lwServer, Registration registration, LwM2MClient lwM2MClient, Set targets, String typeOper) { targets.forEach(target -> { - ResultIds pathIds = new ResultIds(target); - if (pathIds.resourceId >= 0 && lwM2MClient.getModelObjects().get(pathIds.getObjectId()) - .getInstances().get(pathIds.getInstanceId()).getResource(pathIds.getResourceId()).getValue() != null) { +// ResultIds pathIds = new ResultIds(target); + LwM2mPath pathIds = new LwM2mPath(target); + if (pathIds.isResource() && lwM2MClient.getModelObjects().get(pathIds.getObjectId()) + .getInstances().get(pathIds.getObjectInstanceId()).getResource(pathIds.getResourceId()).getValue() != null) { if (GET_TYPE_OPER_READ.equals(typeOper)) { lwM2MTransportRequest.sendAllRequest(lwServer, registration, target, typeOper, ContentFormat.TLV.getName(), null, null, null, this.context.getCtxServer().getTimeout(), @@ -1024,9 +1064,10 @@ public class LwM2MTransportService { private ResourceValue getResourceValue(LwM2MClient lwM2MClient, String path) { ResourceValue resourceValue = null; - ResultIds pathIds = new ResultIds(path); - if (pathIds.getResourceId() > -1) { - LwM2mResource resource = lwM2MClient.getModelObjects().get(pathIds.getObjectId()).getInstances().get(pathIds.getInstanceId()).getResource(pathIds.getResourceId()); +// ResultIds pathIds = new ResultIds(path); + LwM2mPath pathIds = new LwM2mPath(path); + if (pathIds.isResource()) { + LwM2mResource resource = lwM2MClient.getModelObjects().get(pathIds.getObjectId()).getInstances().get(pathIds.getObjectInstanceId()).getResource(pathIds.getResourceId()); if (resource.isMultiInstances()) { if (resource.getValues().size() > 0) { resourceValue = new ResourceValue(); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java index 4d63da3580..ea440a33d0 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java @@ -44,7 +44,6 @@ public class LwM2mServerListener { @Override public void registered(Registration registration, Registration previousReg, Collection previousObsersations) { - service.onRegistered(lhServer, registration, previousObsersations); } @@ -54,6 +53,7 @@ public class LwM2mServerListener { @Override public void updated(RegistrationUpdate update, Registration updatedRegistration, Registration previousRegistration) { + log.info("updated"); service.updatedReg(lhServer, updatedRegistration); } @@ -63,6 +63,7 @@ public class LwM2mServerListener { @Override public void unregistered(Registration registration, Collection observations, boolean expired, Registration newReg) { + log.info("unregistered"); service.unReg(registration, observations); } @@ -71,11 +72,13 @@ public class LwM2mServerListener { public final PresenceListener presenceListener = new PresenceListener() { @Override public void onSleeping(Registration registration) { + log.info("onSleeping"); service.onSleepingDev(registration); } @Override public void onAwake(Registration registration) { + log.info("onAwake"); service.onAwakeDev(registration); } }; @@ -92,8 +95,10 @@ public class LwM2mServerListener { if (registration != null) { try { service.onObservationResponse(registration, observation.getPath().toString(), response); - } catch (java.lang.NullPointerException e) { - log.error(e.toString()); + } catch (Exception e) { + e.printStackTrace(); + log.error("onResponse"); + } } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java index 5fd63fa53f..4c0f314bc1 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java @@ -20,6 +20,7 @@ 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.LwM2mObjectInstance; +import org.eclipse.leshan.core.node.LwM2mPath; import org.eclipse.leshan.core.response.LwM2mResponse; import org.eclipse.leshan.core.response.ReadResponse; import org.eclipse.leshan.core.util.Hex; @@ -29,12 +30,11 @@ import org.eclipse.leshan.server.security.SecurityInfo; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportService; -import org.thingsboard.server.transport.lwm2m.server.ResultIds; +import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; -import java.util.UUID; import java.util.Map; import java.util.Set; -import java.util.Collection; +import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; @@ -61,6 +61,7 @@ public class LwM2MClient implements Cloneable { private Map delayedRequests; private Set delayedRequestsId; private Map responses; + private final LwM2mValueConverterImpl converter; public Object clone() throws CloneNotSupportedException { return super.clone(); @@ -81,11 +82,13 @@ public class LwM2MClient implements Cloneable { * Key , response instance -> resources: value...> */ this.responses = new ConcurrentHashMap<>(); + this.converter = new LwM2mValueConverterImpl(); } /** - * Fill with data -> Model client - * @param path - + * Fill with data -> Model client + * + * @param path - * @param response - */ public void onSuccessHandler(String path, LwM2mResponse response) { @@ -99,9 +102,9 @@ public class LwM2MClient implements Cloneable { private void initValue() { this.responses.forEach((key, resp) -> { - ResultIds pathIds = new ResultIds(key); - if (pathIds.getObjectId() > -1) { - ObjectModel objectModel = ((Collection) this.lwServer.getModelProvider().getObjectModel(registration).getObjectModels()).stream().filter(v -> v.id == pathIds.getObjectId()).collect(Collectors.toList()).get(0); + LwM2mPath pathIds = new LwM2mPath(key); + if (pathIds.isObject() || pathIds.isObjectInstance() || pathIds.isResource()) { + ObjectModel objectModel = this.lwServer.getModelProvider().getObjectModel(registration).getObjectModels().stream().filter(v -> v.id == pathIds.getObjectId()).collect(Collectors.toList()).get(0); if (this.modelObjects.get(pathIds.getObjectId()) != null) { this.modelObjects.get(pathIds.getObjectId()).getInstances().put(((ReadResponse) resp).getContent().getId(), (LwM2mObjectInstance) ((ReadResponse) resp).getContent()); } else { @@ -122,30 +125,39 @@ public class LwM2MClient implements Cloneable { } public ResourceModel.Operations getOperation(String path) { - ResultIds resultIds = new ResultIds(path); - return (this.getModelObjects().get(resultIds.getObjectId()) != null) ? this.getModelObjects().get(resultIds.getObjectId()).getObjectModel().resources.get(resultIds.getResourceId()).operations : ResourceModel.Operations.NONE; + LwM2mPath resultIds = new LwM2mPath(path); + return (this.getModelObjects().get(resultIds.getObjectId()) != null) ? + this.getModelObjects().get(resultIds.getObjectId()).getObjectModel().resources.get(resultIds.getResourceId()).operations : + ResourceModel.Operations.NONE; } - public String getResourceName (String path) { - ResultIds resultIds = new ResultIds(path); + public String getResourceName(String path) { + LwM2mPath resultIds = new LwM2mPath(path); return (this.getModelObjects().get(resultIds.getObjectId()) != null) ? this.getModelObjects().get(resultIds.getObjectId()).getObjectModel().resources.get(resultIds.getResourceId()).name : ""; } /** * @param path - path resource * @return - value of Resource or null - */public String getResourceValue(String path) { + */ + public String getResourceValue(String path) { String resValue = null; - ResultIds pathIds = new ResultIds(path); + LwM2mPath pathIds = new LwM2mPath(path); ModelObject modelObject = this.getModelObjects().get(pathIds.getObjectId()); - if (modelObject != null && modelObject.getInstances().get(pathIds.getInstanceId()) != null) { - LwM2mObjectInstance instance = modelObject.getInstances().get(pathIds.getInstanceId()); + + if (modelObject != null && modelObject.getInstances().get(pathIds.getObjectInstanceId()) != null) { + LwM2mObjectInstance instance = modelObject.getInstances().get(pathIds.getObjectInstanceId()); if (instance.getResource(pathIds.getResourceId()) != null) { - resValue = instance.getResource(pathIds.getResourceId()).getType() == OPAQUE ? - Hex.encodeHexString((byte[]) instance.getResource(pathIds.getResourceId()).getValue()).toLowerCase() : - (instance.getResource(pathIds.getResourceId()).isMultiInstances()) ? - instance.getResource(pathIds.getResourceId()).getValues().toString() : - instance.getResource(pathIds.getResourceId()).getValue().toString(); + try { + resValue = instance.getResource(pathIds.getResourceId()).getType() == OPAQUE ? + Hex.encodeHexString((byte[]) instance.getResource(pathIds.getResourceId()).getValue()).toLowerCase() : + (instance.getResource(pathIds.getResourceId()).isMultiInstances()) ? + instance.getResource(pathIds.getResourceId()).getValues().toString() : +// getValueTypeToString(instance.getResource(pathIds.getResourceId()).getValue(), instance.getResource(pathIds.getResourceId()).getType()); + (String) converter.convertValue(instance.getResource(pathIds.getResourceId()).getValue(), instance.getResource(pathIds.getResourceId()).getType(), ResourceModel.Type.STRING, pathIds); + } catch (Exception e) { + log.warn("getResourceValue [{}]", e.getStackTrace().toString()); + } } } return resValue; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ModelObject.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ModelObject.java index 03dcc5013f..fb0ce90e78 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ModelObject.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ModelObject.java @@ -21,7 +21,7 @@ import org.eclipse.leshan.core.node.LwM2mObjectInstance; import java.util.Map; @Data -public class ModelObject { +public class ModelObject implements Cloneable { /** * model one on all instance * for each instance only id resource with parameters of resources (observe, attr, telemetry) @@ -38,4 +38,8 @@ public class ModelObject { LwM2mObjectInstance instance = this.instances.get(id); return this.instances.remove(id, instance); } + + public ModelObject clone() throws CloneNotSupportedException { + return (ModelObject) super.clone(); + } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index 9024ed0ee2..a35691160c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -177,10 +177,40 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe return doSaveDevice(device, null); } + @CacheEvict(cacheNames = DEVICE_CACHE, key = "{#device.tenantId, #device.name}") + @Override + public Device saveDeviceWithCredentials(Device device, DeviceCredentials deviceCredentials) { + if (device.getId() == null) { + Device deviceWithName = this.findDeviceByTenantIdAndName(device.getTenantId(), device.getName()); + device = deviceWithName == null ? device : deviceWithName.updateDevice(device); + } + Device savedDevice = this.saveDeviceWithoutCredentials(device); + deviceCredentials.setDeviceId(savedDevice.getId()); + if (device.getId() == null) { + deviceCredentials = deviceCredentialsService.createDeviceCredentials(savedDevice.getTenantId(), deviceCredentials); + } + else { + deviceCredentials.setId(deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getTenantId(), savedDevice.getId()).getId()); + deviceCredentials = deviceCredentialsService.updateDeviceCredentials(device.getTenantId(), deviceCredentials); + } + return savedDevice; + } + private Device doSaveDevice(Device device, String accessToken) { + Device savedDevice = this.saveDeviceWithoutCredentials(device); + if (device.getId() == null) { + DeviceCredentials deviceCredentials = new DeviceCredentials(); + deviceCredentials.setDeviceId(new DeviceId(savedDevice.getUuidId())); + deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN); + deviceCredentials.setCredentialsId(!StringUtils.isEmpty(accessToken) ? accessToken : RandomStringUtils.randomAlphanumeric(20)); + deviceCredentialsService.createDeviceCredentials(device.getTenantId(), deviceCredentials); + } + return savedDevice; + } + + private Device saveDeviceWithoutCredentials(Device device) { log.trace("Executing saveDevice [{}]", device); deviceValidator.validate(device, Device::getTenantId); - Device savedDevice; try { DeviceProfile deviceProfile; if (device.getDeviceProfileId() == null) { @@ -198,8 +228,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe } device.setType(deviceProfile.getName()); device.setDeviceData(syncDeviceData(deviceProfile, device.getDeviceData())); - - savedDevice = deviceDao.save(device.getTenantId(), device); + return deviceDao.save(device.getTenantId(), device); } catch (Exception t) { ConstraintViolationException e = extractConstraintViolationException(t).orElse(null); if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("device_name_unq_key")) { @@ -208,14 +237,6 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe throw t; } } - if (device.getId() == null) { - DeviceCredentials deviceCredentials = new DeviceCredentials(); - deviceCredentials.setDeviceId(new DeviceId(savedDevice.getUuidId())); - deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN); - deviceCredentials.setCredentialsId(!StringUtils.isEmpty(accessToken) ? accessToken : RandomStringUtils.randomAlphanumeric(20)); - deviceCredentialsService.createDeviceCredentials(device.getTenantId(), deviceCredentials); - } - return savedDevice; } private DeviceData syncDeviceData(DeviceProfile deviceProfile, DeviceData deviceData) { @@ -530,7 +551,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe @Override protected void validateCreate(TenantId tenantId, Device device) { DefaultTenantProfileConfiguration profileConfiguration = - (DefaultTenantProfileConfiguration)tenantProfileCache.get(tenantId).getProfileData().getConfiguration(); + (DefaultTenantProfileConfiguration) tenantProfileCache.get(tenantId).getProfileData().getConfiguration(); long maxDevices = profileConfiguration.getMaxDevices(); validateNumberOfEntitiesPerTenant(tenantId, deviceDao, maxDevices, EntityType.DEVICE); } diff --git a/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java b/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java index e79bb2b713..17fd9c83c5 100644 --- a/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java +++ b/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java @@ -121,6 +121,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; @@ -1091,6 +1092,24 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable { return restTemplate.postForEntity(baseURL + "/api/device/credentials", deviceCredentials, DeviceCredentials.class).getBody(); } + public Optional saveDeviceWithCredentials(Device device, DeviceCredentials credentials) { + try { + Map, Object> deviceCredentials = new ConcurrentHashMap<>(); + deviceCredentials.put(Device.class, device); + deviceCredentials.put(DeviceCredentials.class, credentials); +// return restTemplate.postForEntity(baseURL + "/api/lwm2m/device-credentials", deviceCredentials, Device.class).getBody(); + ResponseEntity deviceOpt = restTemplate.postForEntity(baseURL + "/api/lwm2m/device-credentials", deviceCredentials, Device.class); + return Optional.ofNullable(deviceOpt.getBody()); + } catch (HttpClientErrorException exception) { + if (exception.getStatusCode() == HttpStatus.NOT_FOUND) { + return Optional.empty(); + } else { + throw exception; + } + } + } + + public PageData getTenantDevices(String type, PageLink pageLink) { Map params = new HashMap<>(); params.put("type", type); From 5eeb12ea13a26c96cd6ac58e32cfc2f3dd9dc865 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 22 Dec 2020 16:24:16 +0200 Subject: [PATCH 008/249] Lwm2m: backEnd: add saveDeviceWithCredential --- application/src/main/resources/thingsboard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 5dfbdbebd8..b5fe6b29cb 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -433,7 +433,7 @@ spring: database-platform: "${SPRING_JPA_DATABASE_PLATFORM:org.hibernate.dialect.PostgreSQLDialect}" datasource: driverClassName: "${SPRING_DRIVER_CLASS_NAME:org.postgresql.Driver}" - url: "${SPRING_DATASOURCE_URL:jdbc:postgresql://localhost:5432/thingsboard_ce_3_2_2}" + url: "${SPRING_DATASOURCE_URL:jdbc:postgresql://localhost:5432/thingsboard_ce_3_3_test}" username: "${SPRING_DATASOURCE_USERNAME:postgres}" password: "${SPRING_DATASOURCE_PASSWORD:postgres}" hikari: From 9df5be790ac109bb3adb5e3aab1c51b32e57fbb8 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Fri, 25 Dec 2020 21:35:13 +0200 Subject: [PATCH 009/249] Lwm2m: backEnd: add ExecutorService to LwM2MTransportService --- .../lwm2m/server/LwM2MTransportHandler.java | 2 + .../lwm2m/server/LwM2MTransportRequest.java | 43 +++-- .../lwm2m/server/LwM2MTransportService.java | 157 +++++++++++------- .../transport/lwm2m/server/ResultIds.java | 38 ----- .../secure/LwM2mInMemorySecurityStore.java | 6 +- .../common/transport/TransportContext.java | 2 + 6 files changed, 126 insertions(+), 122 deletions(-) delete mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ResultIds.java diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportHandler.java index d37b429101..f29649de7d 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportHandler.java @@ -107,6 +107,8 @@ public class LwM2MTransportHandler{ public static final String PUT_TYPE_OPER_WRITE_ATTRIBUTES = "wright-attributes"; public static final String EVENT_AWAKE = "AWAKE"; + public static final String SERVICE_CHANNEL = "SERVICE"; + public static final String RESPONSE_CHANNEL = "RESP"; @Autowired @Qualifier("LeshanServerCert") diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java index 576415da31..2c7721089c 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java @@ -74,26 +74,27 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandle 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.PUT_TYPE_OPER_WRITE_UPDATE; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.RESPONSE_CHANNEL; @Slf4j @Service("LwM2MTransportRequest") @ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' ) || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") public class LwM2MTransportRequest { - private final ExecutorService executorService; - private static final String RESPONSE_CHANNEL = "THINGSBOARD_RESP"; - private final LwM2mValueConverterImpl converter; + private ExecutorService executorResponse; + private ExecutorService executorResponseError; + private LwM2mValueConverterImpl converter; @Autowired LwM2MTransportService service; - public LwM2MTransportRequest() { - this.converter = new LwM2mValueConverterImpl(); - executorService = Executors.newCachedThreadPool( - new NamedThreadFactory(String.format("LwM2M %s channel response", RESPONSE_CHANNEL))); - } @PostConstruct public void init() { + this.converter = new LwM2mValueConverterImpl(); + executorResponse = Executors.newCachedThreadPool( + new NamedThreadFactory(String.format("LwM2M %s channel response", RESPONSE_CHANNEL))); + executorResponseError = Executors.newCachedThreadPool( + new NamedThreadFactory(String.format("LwM2M %s channel response Error", RESPONSE_CHANNEL))); } public Collection doGetRegistrations(LeshanServer lwServer) { @@ -306,27 +307,21 @@ public class LwM2MTransportRequest { } private void handleResponse(Registration registration, final String path, LwM2mResponse response, DownlinkRequest request, LwM2MClient lwM2MClient, boolean isDelayedUpdate) { - executorService.submit(new Runnable() { - @Override - public void run() { - try { - sendResponse(registration, path, response, request, lwM2MClient, isDelayedUpdate); - } catch (RuntimeException t) { - log.error("[{}] endpoint [{}] path [{}] error Unable to after send response.", registration.getEndpoint(), path, t.toString()); - } + executorResponse.submit(() -> { + try { + sendResponse(registration, path, response, request, lwM2MClient, isDelayedUpdate); + } catch (Exception e) { + log.error("[{}] endpoint [{}] path [{}] error Unable to after send response.", registration.getEndpoint(), path, e); } }); } private void handleResponseError(Registration registration, final String path, LwM2MClient lwM2MClient, boolean isDelayedUpdate) { - executorService.submit(new Runnable() { - @Override - public void run() { - try { - if (isDelayedUpdate) lwM2MClient.onSuccessOrErrorDelayedRequests(path); - } catch (RuntimeException t) { - log.error("[{}] endpoint [{}] path [{}] error Unable to after send response.", registration.getEndpoint(), path, t.toString()); - } + executorResponseError.submit(() -> { + try { + if (isDelayedUpdate) lwM2MClient.onSuccessOrErrorDelayedRequests(path); + } catch (RuntimeException t) { + log.error("[{}] endpoint [{}] path [{}] error Unable to after send response.", registration.getEndpoint(), path, t.toString()); } }); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java index 861afa02a8..46282eed07 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -32,6 +32,7 @@ import org.eclipse.leshan.core.observation.Observation; import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.core.request.WriteRequest; import org.eclipse.leshan.core.response.ReadResponse; +import org.eclipse.leshan.core.util.NamedThreadFactory; import org.eclipse.leshan.server.californium.LeshanServer; import org.eclipse.leshan.server.registration.Registration; import org.springframework.beans.factory.annotation.Autowired; @@ -71,6 +72,8 @@ import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Predicate; @@ -89,6 +92,7 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandle import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.LOG_LW2M_TELEMETRY; 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.SERVICE_CHANNEL; import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.getAckCallback; @Slf4j @@ -96,6 +100,10 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandle @ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' ) || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") public class LwM2MTransportService { + private ExecutorService executorRegistered; + private ExecutorService executorUpdateRegistered; + private ExecutorService executorUnRegistered; + @Autowired private TransportService transportService; @@ -111,6 +119,12 @@ public class LwM2MTransportService { @PostConstruct public void init() { context.getScheduler().scheduleAtFixedRate(this::checkInactivityAndReportActivity, new Random().nextInt((int) context.getCtxServer().getSessionReportTimeout()), context.getCtxServer().getSessionReportTimeout(), TimeUnit.MILLISECONDS); + executorRegistered = Executors.newCachedThreadPool( + new NamedThreadFactory(String.format("LwM2M %s channel registered", SERVICE_CHANNEL))); + executorUpdateRegistered = Executors.newCachedThreadPool( + new NamedThreadFactory(String.format("LwM2M %s channel update registered", SERVICE_CHANNEL))); + executorUnRegistered = Executors.newCachedThreadPool( + new NamedThreadFactory(String.format("LwM2M %s channel un registered", SERVICE_CHANNEL))); } /** @@ -129,28 +143,35 @@ public class LwM2MTransportService { * @param previousObsersations - may be null */ public void onRegistered(LeshanServer lwServer, Registration registration, Collection previousObsersations) { - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.updateInSessionsLwM2MClient(lwServer, registration); - if (lwM2MClient != null) { - lwM2MClient.setLwM2MTransportService(this); - lwM2MClient.setLwM2MTransportService(this); - lwM2MClient.setSessionUuid(UUID.randomUUID()); - this.setLwM2MClient(lwServer, registration, lwM2MClient); - SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration.getId()); - if (sessionInfo != null) { - lwM2MClient.setDeviceUuid(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB())); - lwM2MClient.setProfileUuid(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); - lwM2MClient.setDeviceName(sessionInfo.getDeviceName()); - lwM2MClient.setDeviceProfileName(sessionInfo.getDeviceType()); - transportService.registerAsyncSession(sessionInfo, new LwM2MSessionMsgListener(this, sessionInfo)); - transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN), null); - transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), null); - this.sentLogsToThingsboard(LOG_LW2M_INFO + ": Client registration", registration.getId()); - } else { - log.error("Client: [{}] onRegistered [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); + executorRegistered.submit(() -> { + try { + log.info("[{}] Client: onRegistered name ", registration.getEndpoint()); + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.updateInSessionsLwM2MClient(lwServer, registration); + if (lwM2MClient != null) { + lwM2MClient.setLwM2MTransportService(this); + lwM2MClient.setLwM2MTransportService(this); + lwM2MClient.setSessionUuid(UUID.randomUUID()); + this.setLwM2MClient(lwServer, registration, lwM2MClient); + SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration.getId()); + if (sessionInfo != null) { + lwM2MClient.setDeviceUuid(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB())); + lwM2MClient.setProfileUuid(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); + lwM2MClient.setDeviceName(sessionInfo.getDeviceName()); + lwM2MClient.setDeviceProfileName(sessionInfo.getDeviceType()); + transportService.registerAsyncSession(sessionInfo, new LwM2MSessionMsgListener(this, sessionInfo)); + transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN), null); + transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), null); + this.sentLogsToThingsboard(LOG_LW2M_INFO + ": Client registration", registration.getId()); + } else { + log.error("Client: [{}] onRegistered [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); + } + } else { + log.error("Client: [{}] onRegistered [{}] name [{}] lwM2MClient ", registration.getId(), registration.getEndpoint(), null); + } + } catch (Throwable t) { + log.error("[{}] endpoint [{}] error Unable registration.", registration.getEndpoint(), t); } - } else { - log.error("Client: [{}] onRegistered [{}] name [{}] lwM2MClient ", registration.getId(), registration.getEndpoint(), null); - } + }); } /** @@ -158,12 +179,18 @@ public class LwM2MTransportService { * @param registration - Registration LwM2M Client */ public void updatedReg(LeshanServer lwServer, Registration registration) { - SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration.getId()); - if (sessionInfo != null) { - log.info("Client: [{}] updatedReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType()); - } else { - log.error("Client: [{}] updatedReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); - } + executorUpdateRegistered.submit(() -> { + try { + SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration.getId()); + if (sessionInfo != null) { + log.info("Client: [{}] updatedReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType()); + } else { + log.error("Client: [{}] updatedReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); + } + } catch (Throwable t) { + log.error("[{}] endpoint [{}] error Unable update registration.", registration.getEndpoint(), t); + } + }); } /** @@ -172,8 +199,14 @@ public class LwM2MTransportService { * !!! Warn: if have not finishing unReg, then this operation will be finished on next Client`s connect */ public void unReg(Registration registration, Collection observations) { - this.sentLogsToThingsboard(LOG_LW2M_INFO + ": Client unRegistration", registration.getId()); - this.closeClientSession(registration); + executorUpdateRegistered.submit(() -> { + try { + this.sentLogsToThingsboard(LOG_LW2M_INFO + ": Client unRegistration", registration.getId()); + this.closeClientSession(registration); + } catch (Throwable t) { + log.error("[{}] endpoint [{}] error Unable un registration.", registration.getEndpoint(), t); + } + }); } private void closeClientSession(Registration registration) { @@ -848,14 +881,12 @@ public class LwM2MTransportService { * @param deviceProfile - */ public void onDeviceProfileUpdate(TransportProtos.SessionInfoProto sessionInfo, DeviceProfile deviceProfile) { - String registrationId = lwM2mInMemorySecurityStore.getSessions().entrySet() + Set registrationIds = lwM2mInMemorySecurityStore.getSessions().entrySet() .stream() - .filter(e -> e.getValue().getDeviceUuid().equals(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB()))) - .findFirst() - .map(Map.Entry::getKey) - .orElse(""); - if (!registrationId.isEmpty()) { - this.onDeviceUpdateChangeProfile(registrationId, deviceProfile); + .filter(e -> e.getValue().getProfileUuid().equals(deviceProfile.getUuidId())) + .map(Map.Entry::getKey).sorted().collect(Collectors.toSet()); + if (registrationIds.size() > 0) { + this.onDeviceUpdateChangeProfile(registrationIds, deviceProfile); } } @@ -883,19 +914,23 @@ public class LwM2MTransportService { LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getSessions().get(registrationId); lwM2MClient.setDeviceName(device.getName()); if (!lwM2MClient.getProfileUuid().equals(device.getDeviceProfileId().getId())) { - deviceProfileOpt.ifPresent(deviceProfile -> this.onDeviceUpdateChangeProfile(registrationId, deviceProfile)); + Set registrationIds = new HashSet<>(); + registrationIds.add(registrationId); + deviceProfileOpt.ifPresent(deviceProfile -> this.onDeviceUpdateChangeProfile(registrationIds, deviceProfile)); } + + lwM2MClient.setProfileUuid(device.getDeviceProfileId().getId()); } /** * #1 Read new, old Value (Attribute, Telemetry, Observe, KeyName) - * #2 Update in lwM2MClient: ...Profile + * #2 Update in lwM2MClient: ...Profile if changes from update device * #3 Equivalence test: old <> new Value (Attribute, Telemetry, Observe, KeyName) * #3.1 Attribute isChange (add&del) * #3.2 Telemetry isChange (add&del) * #3.3 KeyName isChange (add) * #4 update - * #4.1 add If #3 isChange, then analyze and update Value in Transport form Client and sent Value ti thingsboard + * #4.1 add If #3 isChange, then analyze and update Value in Transport form Client and sent Value to thingsboard * #4.2 del * -- if add attributes includes del telemetry - result del for observe * #5 @@ -905,15 +940,14 @@ public class LwM2MTransportService { * #5.3 Observe.del * -- different between newObserve and oldObserve: sent Request cancel observe to client * - * @param registrationId - - * @param deviceProfile - + * @param registrationIds - + * @param deviceProfile - */ - public void onDeviceUpdateChangeProfile(String registrationId, DeviceProfile deviceProfile) { - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(registrationId); - AttrTelemetryObserveValue attrTelemetryObserveValueOld = lwM2mInMemorySecurityStore.getProfiles().get(lwM2MClient.getProfileUuid()); + public void onDeviceUpdateChangeProfile(Set registrationIds, DeviceProfile deviceProfile) { + + AttrTelemetryObserveValue attrTelemetryObserveValueOld = lwM2mInMemorySecurityStore.getProfiles().get(deviceProfile.getUuidId()); if (lwM2mInMemorySecurityStore.addUpdateProfileParameters(deviceProfile)) { - LeshanServer lwServer = lwM2MClient.getLwServer(); - Registration registration = lwM2mInMemorySecurityStore.getByRegistration(registrationId); + // #1 JsonArray attributeOld = attrTelemetryObserveValueOld.getPostAttributeProfile(); Set attributeSetOld = new Gson().fromJson(attributeOld, Set.class); @@ -929,9 +963,6 @@ public class LwM2MTransportService { Set telemetrySetNew = new Gson().fromJson(telemetryNew, Set.class); JsonArray observeNew = attrTelemetryObserveValueNew.getPostObserveProfile(); JsonObject keyNameNew = attrTelemetryObserveValueNew.getPostKeyNameProfile(); - // #2 - lwM2MClient.setDeviceProfileName(deviceProfile.getName()); - lwM2MClient.setProfileUuid(deviceProfile.getUuidId()); // #3 ResultsAnalyzerParameters sentAttrToThingsboard = new ResultsAnalyzerParameters(); @@ -957,9 +988,15 @@ public class LwM2MTransportService { // #4.1 add if (sentAttrToThingsboard.getPathPostParametersAdd().size() > 0) { // update value in Resources - this.updateResourceValueObserve(lwServer, registration, lwM2MClient, sentAttrToThingsboard.getPathPostParametersAdd(), GET_TYPE_OPER_READ); - // sent attr/telemetry to tingsboard for new path - this.updateAttrTelemetry(registration, false, sentAttrToThingsboard.getPathPostParametersAdd()); + registrationIds.forEach(registrationId -> { + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(registrationId); + LeshanServer lwServer = lwM2MClient.getLwServer(); + Registration registration = lwM2mInMemorySecurityStore.getByRegistration(registrationId); + log.warn("[{}] # 4.1", registration.getEndpoint()); + this.updateResourceValueObserve(lwServer, registration, lwM2MClient, sentAttrToThingsboard.getPathPostParametersAdd(), GET_TYPE_OPER_READ); + // sent attr/telemetry to tingsboard for new path + this.updateAttrTelemetry(registration, false, sentAttrToThingsboard.getPathPostParametersAdd()); + }); } // #4.2 del if (sentAttrToThingsboard.getPathPostParametersDel().size() > 0) { @@ -980,10 +1017,16 @@ public class LwM2MTransportService { // does not include oldObserve ResultsAnalyzerParameters postObserveAnalyzer = this.getAnalyzerParameters(sentObserveToClientOld.getPathPostParametersAdd(), sentObserveToClientNew.getPathPostParametersAdd()); // sent Request observe to Client - this.updateResourceValueObserve(lwServer, registration, lwM2MClient, postObserveAnalyzer.getPathPostParametersAdd(), GET_TYPE_OPER_OBSERVE); - // 5.3 del - // sent Request cancel observe to Client - this.cancelObserveIsValue(lwServer, registration, postObserveAnalyzer.getPathPostParametersDel()); + registrationIds.forEach(registrationId -> { + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(registrationId); + LeshanServer lwServer = lwM2MClient.getLwServer(); + Registration registration = lwM2mInMemorySecurityStore.getByRegistration(registrationId); + log.warn("[{}] # 5.1", registration.getEndpoint()); + this.updateResourceValueObserve(lwServer, registration, lwM2MClient, postObserveAnalyzer.getPathPostParametersAdd(), GET_TYPE_OPER_OBSERVE); + // 5.3 del + // sent Request cancel observe to Client + this.cancelObserveIsValue(lwServer, registration, postObserveAnalyzer.getPathPostParametersDel()); + }); } } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ResultIds.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ResultIds.java deleted file mode 100644 index b5c2f6638e..0000000000 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ResultIds.java +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Copyright © 2016-2020 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.thingsboard.server.transport.lwm2m.server; - -import lombok.Builder; -import lombok.Data; - -@Data -public class ResultIds { - @Builder.Default - int objectId = -1; - @Builder.Default - int instanceId = -1; - @Builder.Default - int resourceId = -1; - - public ResultIds (String path) { - String[] paths = path.split("/"); - if (paths != null && paths.length > 1) { - this.objectId = (paths.length > 1) ? Integer.parseInt(paths[1]) : this.objectId; - this.instanceId = (paths.length > 2) ? Integer.parseInt(paths[2]) : this.instanceId; - this.resourceId = (paths.length > 3) ? Integer.parseInt(paths[3]) : this.resourceId; - } - } -} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java index ceea02e55a..5604017d61 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java @@ -173,16 +173,16 @@ public class LwM2mInMemorySecurityStore extends InMemorySecurityStore { private SecurityInfo add(String identity) { ReadResultSecurityStore store = lwM2MGetSecurityInfo.getSecurityInfo(identity, TypeServer.CLIENT); - UUID profileUuid = (addUpdateProfileParameters(store.getDeviceProfile())) ? store.getDeviceProfile().getUuidId() : null; + UUID profileUuid = (store.getDeviceProfile() != null && addUpdateProfileParameters(store.getDeviceProfile())) ? store.getDeviceProfile().getUuidId() : null; if (store.getSecurityInfo() != null) { if (store.getSecurityMode() < DEFAULT_MODE.code) { String endpoint = store.getSecurityInfo().getEndpoint(); sessions.put(endpoint, new LwM2MClient(endpoint, store.getSecurityInfo().getIdentity(), store.getSecurityInfo(), store.getMsg(), null, null, profileUuid)); } } else { - if (store.getSecurityMode() == NO_SEC.code) + if (store.getSecurityMode() == NO_SEC.code && profileUuid != null) sessions.put(identity, new LwM2MClient(identity, null, null, store.getMsg(), null, null, profileUuid)); - else log.error("Registration failed: FORBIDDEN, endpointId: [{}]", identity); + else log.error("Registration failed: FORBIDDEN/profileUuid [{}] , endpointId: [{}]", profileUuid, identity); } return store.getSecurityInfo(); } diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportContext.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportContext.java index 4b7677dd69..760431b250 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportContext.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportContext.java @@ -43,8 +43,10 @@ public abstract class TransportContext { @Autowired private TransportService transportService; + @Autowired private TbServiceInfoProvider serviceInfoProvider; + @Autowired private SchedulerComponent scheduler; From 9731fb614b1ce09f76e60e46fe6c87a7a9e1525d Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Sat, 26 Dec 2020 22:29:37 +0200 Subject: [PATCH 010/249] Lwm2m: backEnd: add Error securityConfig if not Device or Profile --- .../server/secure/LwM2mInMemorySecurityStore.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java index 5604017d61..72ba277b18 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java @@ -17,6 +17,7 @@ package org.thingsboard.server.transport.lwm2m.server.secure; import com.google.gson.JsonObject; import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.util.Hex; import org.eclipse.leshan.server.californium.LeshanServer; import org.eclipse.leshan.server.registration.Registration; import org.eclipse.leshan.server.security.InMemorySecurityStore; @@ -69,7 +70,8 @@ public class LwM2mInMemorySecurityStore extends InMemorySecurityStore { readLock.lock(); try { String registrationId = this.getByRegistrationId(endPoint, null); - return (registrationId != null && sessions.size() > 0 && sessions.get(registrationId) != null) ? sessions.get(registrationId).getInfo() : this.add(endPoint); + SecurityInfo info = (registrationId != null && sessions.size() > 0 && sessions.get(registrationId) != null) ? sessions.get(registrationId).getInfo() : this.add(endPoint); + return info; } finally { readLock.unlock(); } @@ -182,7 +184,15 @@ public class LwM2mInMemorySecurityStore extends InMemorySecurityStore { } else { if (store.getSecurityMode() == NO_SEC.code && profileUuid != null) sessions.put(identity, new LwM2MClient(identity, null, null, store.getMsg(), null, null, profileUuid)); - else log.error("Registration failed: FORBIDDEN/profileUuid [{}] , endpointId: [{}]", profileUuid, identity); + else { + log.error("Registration failed: FORBIDDEN/profileUuid/device [{}] , endpointId: [{}]", profileUuid, identity); + /** + * Return Error securityInfo + */ + byte[] preSharedKey = Hex.decodeHex("0A0B".toCharArray()); + SecurityInfo info = SecurityInfo.newPreSharedKeyInfo("error", "error_identity", preSharedKey); + return info; + } } return store.getSecurityInfo(); } From c5d82c2203755e75b79c898b9ba7511c1c9d731a Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Sat, 26 Dec 2020 23:09:35 +0200 Subject: [PATCH 011/249] Lwm2m: backEnd: add Error securityConfig --- .../server/transport/lwm2m/server/LwM2MTransportService.java | 2 +- .../lwm2m/server/secure/LwM2mInMemorySecurityStore.java | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java index 46282eed07..59768d1d32 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java index 72ba277b18..07294bccfe 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java @@ -218,7 +218,6 @@ public class LwM2mInMemorySecurityStore extends InMemorySecurityStore { } /** - * * @param deviceProfile */ public boolean addUpdateProfileParameters(DeviceProfile deviceProfile) { From c877609a6200d6b15e4415717155c96c02ffd886 Mon Sep 17 00:00:00 2001 From: VoBa Date: Tue, 29 Dec 2020 11:15:10 +0200 Subject: [PATCH 012/249] Revert default database name --- application/src/main/resources/thingsboard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 5dfbdbebd8..065a0a4cb0 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -433,7 +433,7 @@ spring: database-platform: "${SPRING_JPA_DATABASE_PLATFORM:org.hibernate.dialect.PostgreSQLDialect}" datasource: driverClassName: "${SPRING_DRIVER_CLASS_NAME:org.postgresql.Driver}" - url: "${SPRING_DATASOURCE_URL:jdbc:postgresql://localhost:5432/thingsboard_ce_3_2_2}" + url: "${SPRING_DATASOURCE_URL:jdbc:postgresql://localhost:5432/thingsboard}" username: "${SPRING_DATASOURCE_USERNAME:postgres}" password: "${SPRING_DATASOURCE_PASSWORD:postgres}" hikari: From ff56bd8863691c241201f5843f01ecf29cbb6dbe Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 29 Dec 2020 11:31:59 +0200 Subject: [PATCH 013/249] Lwm2m: backEnd: add add to LwM2MClient only resources (value) --- .../server/LwM2MTransportContextServer.java | 2 +- .../lwm2m/server/LwM2MTransportHandler.java | 88 ++++--- .../lwm2m/server/LwM2MTransportRequest.java | 27 ++- .../lwm2m/server/LwM2MTransportService.java | 217 ++++++++---------- .../lwm2m/server/client/LwM2MClient.java | 72 ++---- .../lwm2m/server/client/ResourceValue.java | 10 + .../secure/LwM2mInMemorySecurityStore.java | 6 +- .../lwm2m/utils/LwM2mValueConverterImpl.java | 8 + .../lwm2m/LwM2MTransportConfigServer.java | 27 +++ 9 files changed, 236 insertions(+), 221 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportContextServer.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportContextServer.java index d107318ad0..7199c3c31c 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportContextServer.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportContextServer.java @@ -58,7 +58,7 @@ public class LwM2MTransportContextServer extends TransportContext { private LwM2MTransportConfigServer ctxServer; @Autowired - LwM2MTransportConfigServer lwM2MTransportConfigServer; + protected LwM2MTransportConfigServer lwM2MTransportConfigServer; @Autowired private TransportService transportService; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportHandler.java index f29649de7d..1e84af7d48 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportHandler.java @@ -27,7 +27,9 @@ 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.util.Hex; import org.eclipse.leshan.server.californium.LeshanServer; import org.eclipse.leshan.server.californium.LeshanServerBuilder; @@ -53,7 +55,7 @@ import java.util.Optional; @Slf4j @Component("LwM2MTransportHandler") @ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' )|| ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") -public class LwM2MTransportHandler{ +public class LwM2MTransportHandler { // We choose a default timeout a bit higher to the MAX_TRANSMIT_WAIT(62-93s) which is the time from starting to // send a Confirmable message to the time when an acknowledgement is no longer expected. @@ -132,8 +134,7 @@ public class LwM2MTransportHandler{ this.lhServerNoSecPskRpk.getRegistrationService().addListener(lwM2mServerListener.registrationListener); this.lhServerNoSecPskRpk.getPresenceService().addListener(lwM2mServerListener.presenceListener); this.lhServerNoSecPskRpk.getObservationService().addListener(lwM2mServerListener.observationListener); - } - catch (java.lang.NullPointerException e) { + } catch (java.lang.NullPointerException e) { log.error("init [{}]", e.toString()); } } @@ -151,31 +152,49 @@ public class LwM2MTransportHandler{ return coapConfig; } - public static String getValueTypeToString (Object value, ResourceModel.Type type, int val) { - try{ +// public static String getValueTypeToString (Object value, ResourceModel.Type type, int val) { +// try{ +// switch (type) { +// case STRING: // String +// case OBJLNK: // ObjectLink +// return value.toString(); +// case INTEGER: // Long +// return Long.toString((long) value); +// case BOOLEAN: // Boolean +// return Boolean.toString((Boolean) value); +// case FLOAT: // Double +// return Double.toString((Double) value); +// case TIME: // Date +// return Long.toString(((Date) value).getTime()); +//// String DATE_FORMAT = "MMM d, yyyy HH:mm a"; +//// DateFormat formatter = new SimpleDateFormat(DATE_FORMAT); +//// return formatter.format(new Date(Integer.toUnsignedLong((Integer) value))); +// case OPAQUE: // byte[] value, base64 +// return Hex.encodeHexString((byte[])value); +// default: +// return null; +// } +// } catch (Exception e) { +// log.error(e.getStackTrace().toString()); +// return null; +// } +// } + + public static boolean equalsResourceValue(Object valueOld, Object valueNew, ResourceModel.Type type, LwM2mPath resourcePath) throws CodecException { switch (type) { - case STRING: // String - case OBJLNK: // ObjectLink - return value.toString(); - case INTEGER: // Long - return Long.toString((long) value); - case BOOLEAN: // Boolean - return Boolean.toString((Boolean) value); - case FLOAT: // Double - return Double.toString((Double) value); - case TIME: // Date - return Long.toString(((Date) value).getTime()); -// String DATE_FORMAT = "MMM d, yyyy HH:mm a"; -// DateFormat formatter = new SimpleDateFormat(DATE_FORMAT); -// return formatter.format(new Date(Integer.toUnsignedLong((Integer) value))); - case OPAQUE: // byte[] value, base64 - return Hex.encodeHexString((byte[])value); + case BOOLEAN: + case INTEGER: + case FLOAT: + return String.valueOf(valueOld).equals(String.valueOf(valueNew)); + case TIME: + return ((Date) valueOld).getTime() == ((Date) valueNew).getTime(); + case STRING: + case OBJLNK: + return valueOld.equals(valueNew); + case OPAQUE: + return Hex.decodeHex(((String) valueOld).toCharArray()).equals(Hex.decodeHex(((String) valueNew).toCharArray())); default: - return null; - } - } catch (Exception e) { - log.error(e.getStackTrace().toString()); - return null; + throw new CodecException("Invalid value type for resource %s, type %s", resourcePath, type); } } @@ -198,19 +217,18 @@ public class LwM2MTransportHandler{ attrTelemetryObserveValue.setPostAttributeProfile(profilesConfigData.get(ATTRIBUTE).getAsJsonArray()); attrTelemetryObserveValue.setPostTelemetryProfile(profilesConfigData.get(TELEMETRY).getAsJsonArray()); attrTelemetryObserveValue.setPostObserveProfile(profilesConfigData.get(OBSERVE).getAsJsonArray()); - return attrTelemetryObserveValue; + return attrTelemetryObserveValue; } /** - * @return deviceProfileBody with Observe&Attribute&Telemetry From Thingsboard * Example: with pathResource (use only pathResource) * property: "observeAttr" * {"keyName": { - * "/3/0/1": "modelNumber", - * "/3/0/0": "manufacturer", - * "/3/0/2": "serialNumber" - * }, + * "/3/0/1": "modelNumber", + * "/3/0/0": "manufacturer", + * "/3/0/2": "serialNumber" + * }, * "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"]} @@ -312,12 +330,12 @@ public class LwM2MTransportHandler{ } } - public static String splitCamelCaseString(String s){ + public static String splitCamelCaseString(String s) { LinkedList linkedListOut = new LinkedList<>(); LinkedList linkedList = new LinkedList((Arrays.asList(s.split(" ")))); - linkedList.forEach(str-> { + linkedList.forEach(str -> { String strOut = str.replaceAll("\\W", "").replaceAll("_", "").toUpperCase(); - if (strOut.length()>1) linkedListOut.add(strOut.charAt(0) + strOut.substring(1).toLowerCase()); + if (strOut.length() > 1) linkedListOut.add(strOut.charAt(0) + strOut.substring(1).toLowerCase()); else linkedListOut.add(strOut); }); linkedListOut.set(0, (linkedListOut.get(0).substring(0, 1).toLowerCase() + linkedListOut.get(0).substring(1))); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java index 2c7721089c..f0b96d0225 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java @@ -123,10 +123,7 @@ public class LwM2MTransportRequest { if (registration != null && resultIds.getObjectId() >= 0) { DownlinkRequest request = null; ContentFormat contentFormat = contentFormatParam != null ? ContentFormat.fromName(contentFormatParam.toUpperCase()) : null; - ResourceModel resource = (resultIds.getResourceId() !=null && lwM2MClient != null) ? - lwM2MClient.getModelObjects().get(resultIds.getObjectId()).getObjectModel().resources.get(resultIds.getResourceId()) : null; - ResourceModel.Type resType = (resource == null) ? null : resource.type; - boolean resMultiple = (resource == null) ? false : resource.multiple; + ResourceModel resource = service.context.getCtxServer().getResourceModel(resultIds); timeoutInMs = timeoutInMs > 0 ? timeoutInMs : DEFAULT_TIMEOUT; switch (typeOper) { case GET_TYPE_OPER_READ: @@ -148,21 +145,23 @@ public class LwM2MTransportRequest { request = new CancelObservationRequest(observation); break; case POST_TYPE_OPER_EXECUTE: - if (params != null && !resMultiple) { + if (params != null && resource != null && !resource.multiple) { // request = new ExecuteRequest(target, LwM2MTransportHandler.getValueTypeToString(params, resType)); - request = new ExecuteRequest(target, (String) this.converter.convertValue(params, resType, ResourceModel.Type.STRING, resultIds)); + request = new ExecuteRequest(target, (String) this.converter.convertValue(params, resource.type, ResourceModel.Type.STRING, resultIds)); } else { request = new ExecuteRequest(target); } break; case POST_TYPE_OPER_WRITE_REPLACE: // Request to write a String Single-Instance Resource using the TLV content format. - if (contentFormat.equals(ContentFormat.TLV) && !resMultiple) { - request = this.getWriteRequestSingleResource(null, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), params, resType, registration); - } - // Mode.REPLACE && Request to write a String Single-Instance Resource using the given content format (TEXT, TLV, JSON) - else if (!contentFormat.equals(ContentFormat.TLV) && !resMultiple) { - request = this.getWriteRequestSingleResource(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), params, resType, registration); + if (resource != null) { + if (contentFormat.equals(ContentFormat.TLV) && !resource.multiple) { + request = this.getWriteRequestSingleResource(null, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), params, resource.type, registration); + } + // Mode.REPLACE && Request to write a String Single-Instance Resource using the given content format (TEXT, TLV, JSON) + else if (!contentFormat.equals(ContentFormat.TLV) && !resource.multiple) { + request = this.getWriteRequestSingleResource(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), params, resource.type, registration); + } } break; case PUT_TYPE_OPER_WRITE_UPDATE: @@ -217,10 +216,10 @@ public class LwM2MTransportRequest { break; default: } + if (request != null) { this.sendRequest(lwServer, registration, request, lwM2MClient, timeoutInMs, isDelayedUpdate); - } - else if (request == null && isDelayedUpdate) { + } else if (request == null && isDelayedUpdate) { String msg = String.format(LOG_LW2M_ERROR + ": sendRequest: Resource path - %s msg No SendRequest to Client", target); service.sentLogsToThingsboard(msg, registration.getId()); log.error("[{}] - [{}] No SendRequest", target); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java index 59768d1d32..5e4d4198f0 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java @@ -19,8 +19,8 @@ import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import lombok.SneakyThrows; 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.LwM2mMultipleResource; import org.eclipse.leshan.core.node.LwM2mObject; @@ -55,12 +55,12 @@ import org.thingsboard.server.transport.lwm2m.server.client.ModelObject; import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue; import org.thingsboard.server.transport.lwm2m.server.client.ResultsAnalyzerParameters; import org.thingsboard.server.transport.lwm2m.server.secure.LwM2mInMemorySecurityStore; +import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import javax.annotation.PostConstruct; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -103,6 +103,8 @@ public class LwM2MTransportService { private ExecutorService executorRegistered; private ExecutorService executorUpdateRegistered; private ExecutorService executorUnRegistered; + private LwM2mValueConverterImpl converter; + @Autowired private TransportService transportService; @@ -118,13 +120,14 @@ public class LwM2MTransportService { @PostConstruct public void init() { - context.getScheduler().scheduleAtFixedRate(this::checkInactivityAndReportActivity, new Random().nextInt((int) context.getCtxServer().getSessionReportTimeout()), context.getCtxServer().getSessionReportTimeout(), TimeUnit.MILLISECONDS); - executorRegistered = Executors.newCachedThreadPool( + this.context.getScheduler().scheduleAtFixedRate(this::checkInactivityAndReportActivity, new Random().nextInt((int) context.getCtxServer().getSessionReportTimeout()), context.getCtxServer().getSessionReportTimeout(), TimeUnit.MILLISECONDS); + this.executorRegistered = Executors.newCachedThreadPool( new NamedThreadFactory(String.format("LwM2M %s channel registered", SERVICE_CHANNEL))); - executorUpdateRegistered = Executors.newCachedThreadPool( + this.executorUpdateRegistered = Executors.newCachedThreadPool( new NamedThreadFactory(String.format("LwM2M %s channel update registered", SERVICE_CHANNEL))); - executorUnRegistered = Executors.newCachedThreadPool( + this.executorUnRegistered = Executors.newCachedThreadPool( new NamedThreadFactory(String.format("LwM2M %s channel un registered", SERVICE_CHANNEL))); + this.converter = new LwM2mValueConverterImpl(); } /** @@ -148,7 +151,6 @@ public class LwM2MTransportService { log.info("[{}] Client: onRegistered name ", registration.getEndpoint()); LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.updateInSessionsLwM2MClient(lwServer, registration); if (lwM2MClient != null) { - lwM2MClient.setLwM2MTransportService(this); lwM2MClient.setLwM2MTransportService(this); lwM2MClient.setSessionUuid(UUID.randomUUID()); this.setLwM2MClient(lwServer, registration, lwM2MClient); @@ -183,6 +185,8 @@ public class LwM2MTransportService { try { SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration.getId()); if (sessionInfo != null) { +// transportService.reportActivity(sessionInfo); +// transportService.registerAsyncSession(sessionInfo, new LwM2MSessionMsgListener(this, sessionInfo)); log.info("Client: [{}] updatedReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType()); } else { log.error("Client: [{}] updatedReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); @@ -199,7 +203,7 @@ public class LwM2MTransportService { * !!! Warn: if have not finishing unReg, then this operation will be finished on next Client`s connect */ public void unReg(Registration registration, Collection observations) { - executorUpdateRegistered.submit(() -> { + executorUnRegistered.submit(() -> { try { this.sentLogsToThingsboard(LOG_LW2M_INFO + ": Client unRegistration", registration.getId()); this.closeClientSession(registration); @@ -262,6 +266,7 @@ public class LwM2MTransportService { } /** + * #0 Add new ObjectModel to context * Create new LwM2MClient for current session -> setModelClient... * #1 Add all ObjectLinks (instance) to control the process of executing requests to the client * to get the client model with current values @@ -272,6 +277,8 @@ public class LwM2MTransportService { * @param lwM2MClient - object with All parameters off client */ private void setLwM2MClient(LeshanServer lwServer, Registration registration, LwM2MClient lwM2MClient) { + // #0 + this.setNewObjectModels(lwServer, registration); // #1 Arrays.stream(registration.getObjectLinks()).forEach(url -> { LwM2mPath pathIds = new LwM2mPath(url.getUrl()); @@ -289,6 +296,16 @@ public class LwM2MTransportService { }); } + private void setNewObjectModels(LeshanServer lwServer, Registration registration) { + Arrays.stream(registration.getObjectLinks()).forEach(url -> { + LwM2mPath pathIds = new LwM2mPath(url.getUrl()); + if (pathIds.isObjectInstance() && !pathIds.isResource() && !context.getCtxServer().getObjectModels().containsKey(pathIds.getObjectId())) { + ObjectModel model = lwServer.getModelProvider().getObjectModel(registration).getObjectModels().stream().filter(v -> v.id == pathIds.getObjectId()).collect(Collectors.toList()).get(0); + context.getCtxServer().getObjectModels().put(pathIds.getObjectId(), model); + } + }); + } + /** * @param registrationId - Id of Registration LwM2M Client * @return - sessionInfo after access connect client @@ -396,8 +413,8 @@ public class LwM2MTransportService { lwM2MClient.getDelayedRequests().forEach((k, v) -> { List listV = new ArrayList(); listV.add(v.getKv()); - this.putDelayedUpdateResourcesClient(lwM2MClient, lwM2MClient.getResourceValue(k), getJsonObject(listV).get(v.getKv().getKey()), k); - System.out.printf(" k: %s, v: %s%n, v1: %s%n", k, v.getKv().getStringV(), lwM2MClient.getResourceValue(k)); + this.putDelayedUpdateResourcesClient(lwM2MClient, this.getResourceValueToString(lwM2MClient, k), getJsonObject(listV).get(v.getKv().getKey()), k); + System.out.printf(" k: %s, v: %s%n, v1: %s%n", k, v.getKv().getStringV(), this.getResourceValueToString(lwM2MClient, k)); }); lwM2MClient.getDelayedRequestsId().remove(attributesResponse.getRequestId()); if (lwM2MClient.getDelayedRequests().size() == 0) { @@ -427,10 +444,11 @@ public class LwM2MTransportService { ConcurrentMap keyNamesMap = new Gson().fromJson(profile.getPostKeyNameProfile().toString(), ConcurrentHashMap.class); ConcurrentMap keyNamesIsWritable = keyNamesMap.entrySet() .stream() - .filter(e -> (attrSet.contains(e.getKey()) && lwM2MClient.getOperation(e.getKey()).isWritable())) + .filter(e -> (attrSet.contains(e.getKey()) && context.getCtxServer().getResourceModel(new LwM2mPath(e.getKey())) != null && + context.getCtxServer().getResourceModel(new LwM2mPath(e.getKey())).operations.isWritable())) .collect(Collectors.toConcurrentMap(Map.Entry::getKey, Map.Entry::getValue)); namesIsIsWritable.addAll(new HashSet<>(keyNamesIsWritable.values())); - keyNamesIsWritable.keySet().forEach(p -> namesIsIsWritable.add(lwM2MClient.getResourceName(p))); + keyNamesIsWritable.keySet().forEach(p -> namesIsIsWritable.add(this.getResourceName(p))); return new ArrayList<>(namesIsIsWritable); } @@ -501,7 +519,7 @@ public class LwM2MTransportService { LwM2mPath pathIds = new LwM2mPath(p.getAsString().toString()); if (pathIds.isResource()) { if (path == null || path.contains(p.getAsString())) { - this.addParameters(p.getAsString().toString(), attributes, registration, "attributes"); + this.addParameters(p.getAsString().toString(), attributes, registration); } } }); @@ -510,7 +528,7 @@ public class LwM2MTransportService { LwM2mPath pathIds = new LwM2mPath(p.getAsString().toString()); if (pathIds.isResource()) { if (path == null || path.contains(p.getAsString())) { - this.addParameters(p.getAsString().toString(), telemetry, registration, "telemetry"); + this.addParameters(p.getAsString().toString(), telemetry, registration); } } }); @@ -520,13 +538,15 @@ public class LwM2MTransportService { * @param parameters - JsonObject attributes/telemetry * @param registration - Registration LwM2M Client */ - private void addParameters(String path, JsonObject parameters, Registration registration, String nameParam) { - JsonObject names = lwM2mInMemorySecurityStore.getProfiles().get(lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getProfileUuid()).getPostKeyNameProfile(); + private void addParameters(String path, JsonObject parameters, Registration registration) { + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getSessions().get(registration.getId()); + JsonObject names = lwM2mInMemorySecurityStore.getProfiles().get(lwM2MClient.getProfileUuid()).getPostKeyNameProfile(); String resName = String.valueOf(names.get(path)); if (resName != null && !resName.isEmpty()) { String resValue = null; try { - resValue = lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getResourceValue(path); +// resValue = lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getResourceValueString(path); + resValue = this.getResourceValueToString(lwM2MClient, path); if (resValue != null) { // log.info("addParameters Path: [{}] ResValue : [{}] nameParam [{}]", path, lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getResourceValue(path), nameParam); parameters.addProperty(resName, resValue); @@ -577,7 +597,7 @@ public class LwM2MTransportService { p.getAsString().toString() : null; if (target != null) { // #2 - if (lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getResourceValue(target) != null) { + if (this.getResourceValueToString(lwM2mInMemorySecurityStore.getSessions().get(registration.getId()), target) != null) { lwM2MTransportRequest.sendAllRequest(lwServer, registration, target, GET_TYPE_OPER_OBSERVE, null, null, null, null, this.context.getCtxServer().getTimeout(), false); @@ -635,7 +655,7 @@ public class LwM2MTransportService { * @param path - observe * @param response - observe */ - @SneakyThrows + public void onObservationResponse(Registration registration, String path, ReadResponse response) { if (response.getContent() != null) { if (response.getContent() instanceof LwM2mObject) { @@ -655,13 +675,8 @@ public class LwM2MTransportService { /** * Sending observe value of resources to thingsboard - * #1 Return old Resource from ModelObject - * #2 Create new Resource with value from observation - * #3 Create new Resources from old Resources - * #4 Update new Resources (replace old Resource on new Resource) - * #5 Remove old Instance from modelClient - * #6 Create new Instance with new Resources values - * #7 Update modelClient.getModelObjects(idObject) (replace old Instance on new Instance) + * #1 Return old Value Resource from LwM2MClient + * #2 Update new Resources (replace old Resource Value on new Resource Value) * * @param registration - Registration LwM2M Client * @param value - LwM2mSingleResource response.getContent() @@ -669,72 +684,38 @@ public class LwM2MTransportService { * @param path - resource */ private void onObservationSetResourcesValue(Registration registration, Object value, Map values, String path) { + CountDownLatch respLatch = new CountDownLatch(1); + boolean isChange = false; try { - CountDownLatch respLatch = new CountDownLatch(1); - try { - // #1 - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(registration.getId()); - LwM2mPath resultIds = new LwM2mPath(path); - log.warn("#0 nameDevice: [{}] resultIds: [{}] value: [{}], values: [{}] ", lwM2MClient.getDeviceName(), resultIds, value, values); - ResourceModel.Type resType = lwM2MClient.getModelObjects().get(resultIds.getObjectId()).getObjectModel().resources.get(resultIds.getResourceId()).type; - Map instancesModelObject = (lwM2MClient.getModelObjects().get(resultIds.getObjectId()) != null) ? lwM2MClient.getModelObjects().get(resultIds.getObjectId()).getInstances() : null; - Map resourcesOld = null; - try { - CountDownLatch respResLatch = new CountDownLatch(1); - try { - resourcesOld = (instancesModelObject != null && - instancesModelObject.get(resultIds.getObjectInstanceId()) != null && - instancesModelObject.get(resultIds.getObjectInstanceId()).getResources() != null) ? instancesModelObject.get(resultIds.getObjectInstanceId()).getResources() : null; - - } finally { - respResLatch.countDown(); - } - try { - respResLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); - } catch (InterruptedException ex) { - ex.printStackTrace(); - log.error("#1_2 Update ResourcesValue after Observation in CountDownLatch is unsuccessfully path: [{}] value: [{}]", path, value); - } - } catch (Exception e) { - e.printStackTrace(); - log.error("#1_2_1 Update ResourcesValue after Observation in CountDownLatch is unsuccessfully path: [{}] value: [{}]", path, value); - } - LwM2mResource resourceOld = (resourcesOld != null && resourcesOld.get(resultIds.getResourceId()) != null) ? resourcesOld.get(resultIds.getResourceId()) : null; - // #2 - LwM2mResource resourceNew = null; - if ((resourceOld != null && resourceOld.isMultiInstances() && !resourceOld.getValues().equals(values)) || - (resourceOld == null && value == null)) { - resourceNew = LwM2mMultipleResource.newResource(resultIds.getResourceId(), values, resType); - } else if ((resourceOld != null && !resourceOld.isMultiInstances() && !resourceOld.getValue().equals(values)) || - (resourceOld == null && value != null)) { - resourceNew = LwM2mSingleResource.newResource(resultIds.getResourceId(), value, resType); - } - if (resourceNew != null) { - //#3 - Map resourcesNew = (resourcesOld == null) ? new HashMap<>() : new HashMap<>(resourcesOld); - // #4 - if ((resourceOld != null)) resourcesNew.remove(resourceOld); - // #5 - resourcesNew.put(resultIds.getResourceId(), resourceNew); - // #6 - LwM2mObjectInstance instanceNew = new LwM2mObjectInstance(resultIds.getObjectInstanceId(), resourcesNew.values()); - // #7 - lwM2MClient.getModelObjects().get(resultIds.getObjectId()).removeInstance(resultIds.getObjectInstanceId()); - instancesModelObject.put(resultIds.getObjectInstanceId(), instanceNew); - Set paths = new HashSet<>(); - paths.add(path); - this.updateAttrTelemetry(registration, false, paths); - } - } finally { - respLatch.countDown(); - } - try { - respLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); - } catch (InterruptedException ex) { - ex.printStackTrace(); - log.error("#1_1 Update ResourcesValue after Observation in CountDownLatch is unsuccessfully path: [{}] value: [{}]", path, value); + // #1 + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(registration.getId()); + LwM2mPath pathIds = new LwM2mPath(path); + log.warn("#0 nameDevice: [{}] resultIds: [{}] value: [{}], values: [{}] ", lwM2MClient.getDeviceName(), pathIds, value, values); + ResourceModel.Type resModelType = context.getCtxServer().getResourceModelType(pathIds); + ResourceValue resValueOld = lwM2MClient.getResources().get(path); + // #2 + if (resValueOld.isMultiInstances() && !values.toString().equals(resValueOld.getResourceValue().toString())) { + ResourceValue resourceValue = new ResourceValue ( values, null, true); + lwM2MClient.getResources().put(path, resourceValue); + isChange = true; + } else if (!LwM2MTransportHandler.equalsResourceValue(resValueOld.getValue(), value, resModelType, pathIds)) { + ResourceValue resourceValue = new ResourceValue ( null, value, false); + lwM2MClient.getResources().put(path, resourceValue); + isChange = true; } - } catch (Exception ignored) { + } finally { + respLatch.countDown(); + } + try { + respLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); + } catch (InterruptedException ex) { + ex.printStackTrace(); + log.error("#1_1 Update ResourcesValue after Observation in CountDownLatch is unsuccessfully path: [{}] value: [{}]", path, value); + } + if (isChange) { + Set paths = new HashSet<>(); + paths.add(path); + this.updateAttrTelemetry(registration, false, paths); } } @@ -762,19 +743,19 @@ public class LwM2MTransportService { String value = de.getValue().getAsString(); LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getSession(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())).entrySet().iterator().next().getValue(); AttrTelemetryObserveValue profile = lwM2mInMemorySecurityStore.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); + ResourceModel resourceModel = context.getCtxServer().getResourceModel(new LwM2mPath(path)); if (path != null && (this.validatePathInAttrProfile(profile, path) || this.validatePathInTelemetryProfile(profile, path))) { - if (lwM2MClient.getOperation(path).isWritable()) { + if (resourceModel != null && resourceModel.operations.isWritable()) { lwM2MTransportRequest.sendAllRequest(lwM2MClient.getLwServer(), lwM2MClient.getRegistration(), path, POST_TYPE_OPER_WRITE_REPLACE, ContentFormat.TLV.getName(), lwM2MClient, null, value, this.context.getCtxServer().getTimeout(), false); -// log.info("[{}] path onAttributeUpdate", path); } else { - log.error(LOG_LW2M_ERROR + ": Resource path - [{}] value - [{}] is not Writable and cannot be updated", path, value); + log.error("Resource path - [{}] value - [{}] is not Writable and cannot be updated", path, value); String logMsg = String.format(LOG_LW2M_ERROR + ": attributeUpdate: Resource path - %s value - %s is not Writable and cannot be updated", path, value); this.sentLogsToThingsboard(logMsg, lwM2MClient.getRegistration().getId()); } } else { - log.error(LOG_LW2M_ERROR + ": Attribute name - [{}] value - [{}] is not present as attribute in profile and cannot be updated", de.getKey(), value); + log.error("Attribute name - [{}] value - [{}] is not present as attribute in profile and cannot be updated", de.getKey(), value); String logMsg = String.format(LOG_LW2M_ERROR + ": attributeUpdate: attribute name - %s value - %s is not present as attribute in profile and cannot be updated", de.getKey(), value); this.sentLogsToThingsboard(logMsg, lwM2MClient.getRegistration().getId()); } @@ -845,7 +826,8 @@ public class LwM2MTransportService { Predicate> predicateObj = (obj -> { return obj.getValue().getObjectModel().resources.entrySet().stream().filter(predicateRes).findFirst().isPresent(); }); - Map.Entry object = lwM2MClient.getModelObjects().entrySet().stream().filter(predicateObj).findFirst().get(); +// Map.Entry object = lwM2MClient.getModelObjects().entrySet().stream().filter(predicateObj).findFirst().get(); + Map.Entry object = null; ModelObject modelObject = object.getValue(); LwM2mObjectInstance instance = modelObject.getInstances().entrySet().stream().findFirst().get().getValue(); ResourceModel resource = modelObject.getObjectModel().resources.entrySet().stream().filter(predicateRes).findFirst().get().getValue(); @@ -867,7 +849,8 @@ public class LwM2MTransportService { // ResultIds resultIds = new ResultIds(path); LwM2mPath resultIds = new LwM2mPath(path); LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(registration.getId()); - LwM2mResource resource = lwM2MClient.getModelObjects().get(resultIds.getObjectId()).getInstances().get(resultIds.getObjectInstanceId()).getResource(resultIds.getResourceId()); +// LwM2mResource resource = lwM2MClient.getModelObjects().get(resultIds.getObjectId()).getInstances().get(resultIds.getObjectInstanceId()).getResource(resultIds.getResourceId()); + LwM2mResource resource = null; if (resource.isMultiInstances()) { this.onObservationSetResourcesValue(registration, null, ((LwM2mSingleResource) request.getNode()).getValues(), path); } else { @@ -1080,8 +1063,9 @@ public class LwM2MTransportService { targets.forEach(target -> { // ResultIds pathIds = new ResultIds(target); LwM2mPath pathIds = new LwM2mPath(target); - if (pathIds.isResource() && lwM2MClient.getModelObjects().get(pathIds.getObjectId()) - .getInstances().get(pathIds.getObjectInstanceId()).getResource(pathIds.getResourceId()).getValue() != null) { +// if (pathIds.isResource() && lwM2MClient.getModelObjects().get(pathIds.getObjectId()) +// .getInstances().get(pathIds.getObjectInstanceId()).getResource(pathIds.getResourceId()).getValue() != null) { + if (pathIds.isResource()) { if (GET_TYPE_OPER_READ.equals(typeOper)) { lwM2MTransportRequest.sendAllRequest(lwServer, registration, target, typeOper, ContentFormat.TLV.getName(), null, null, null, this.context.getCtxServer().getTimeout(), @@ -1098,32 +1082,17 @@ public class LwM2MTransportService { private void cancelObserveIsValue(LeshanServer lwServer, Registration registration, Set paramAnallyzer) { LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(registration.getId()); paramAnallyzer.forEach(p -> { - if (this.getResourceValue(lwM2MClient, p) != null) { + if (this.getResourceValue(lwM2MClient, new LwM2mPath(p)) != null) { this.setCancelObservationRecourse(lwServer, registration, p); } } ); } - private ResourceValue getResourceValue(LwM2MClient lwM2MClient, String path) { + private ResourceValue getResourceValue(LwM2MClient lwM2MClient, LwM2mPath pathIds) { ResourceValue resourceValue = null; -// ResultIds pathIds = new ResultIds(path); - LwM2mPath pathIds = new LwM2mPath(path); if (pathIds.isResource()) { - LwM2mResource resource = lwM2MClient.getModelObjects().get(pathIds.getObjectId()).getInstances().get(pathIds.getObjectInstanceId()).getResource(pathIds.getResourceId()); - if (resource.isMultiInstances()) { - if (resource.getValues().size() > 0) { - resourceValue = new ResourceValue(); - resourceValue.setMultiInstances(resource.isMultiInstances()); - resourceValue.setValues(resource.getValues()); - } - } else { - if (resource.getValue() != null) { - resourceValue = new ResourceValue(); - resourceValue.setMultiInstances(resource.isMultiInstances()); - resourceValue.setValue(resource.getValue()); - } - } + resourceValue = lwM2MClient.getResources().get(pathIds.toString()); } return resourceValue; } @@ -1174,4 +1143,20 @@ public class LwM2MTransportService { } } + private String getResourceName(String path) { + LwM2mPath resultIds = new LwM2mPath(path); + return (context.getCtxServer().getObjectModels().get(resultIds.getObjectId()) != null) ? + context.getCtxServer().getObjectModels().get(resultIds.getObjectId()).resources.get(resultIds.getResourceId()).name : ""; + } + + /** + * @param path - path resource + * @return - value of Resource or null + */ + public String getResourceValueToString(LwM2MClient lwM2MClient, String path) { + LwM2mPath pathIds = new LwM2mPath(path); + ResourceValue resourceValue = this.getResourceValue(lwM2MClient, pathIds); + return (String) this.converter.convertValue(resourceValue.getResourceValue(), this.context.getCtxServer().getResourceModelType(pathIds), ResourceModel.Type.STRING, pathIds); + } + } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java index 4c0f314bc1..89ef741da9 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java @@ -18,12 +18,10 @@ package org.thingsboard.server.transport.lwm2m.server.client; import lombok.Data; 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.LwM2mObjectInstance; import org.eclipse.leshan.core.node.LwM2mPath; import org.eclipse.leshan.core.response.LwM2mResponse; import org.eclipse.leshan.core.response.ReadResponse; -import org.eclipse.leshan.core.util.Hex; import org.eclipse.leshan.server.californium.LeshanServer; import org.eclipse.leshan.server.registration.Registration; import org.eclipse.leshan.server.security.SecurityInfo; @@ -38,8 +36,6 @@ import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; -import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE; - @Slf4j @Data public class LwM2MClient implements Cloneable { @@ -56,7 +52,7 @@ public class LwM2MClient implements Cloneable { private Registration registration; private ValidateDeviceCredentialsResponseMsg credentialsResponse; private Map attributes; - private Map modelObjects; + private Map resources; private Set pendingRequests; private Map delayedRequests; private Set delayedRequestsId; @@ -67,15 +63,15 @@ public class LwM2MClient implements Cloneable { return super.clone(); } - public LwM2MClient(String endPoint, String identity, SecurityInfo info, ValidateDeviceCredentialsResponseMsg credentialsResponse, Map attributes, Map modelObjects, UUID profileUuid) { + public LwM2MClient(String endPoint, String identity, SecurityInfo info, ValidateDeviceCredentialsResponseMsg credentialsResponse, Map attributes, UUID profileUuid) { this.endPoint = endPoint; this.identity = identity; this.info = info; this.credentialsResponse = credentialsResponse; this.attributes = (attributes != null && attributes.size() > 0) ? attributes : new ConcurrentHashMap(); - this.modelObjects = (modelObjects != null && modelObjects.size() > 0) ? modelObjects : new ConcurrentHashMap(); this.pendingRequests = ConcurrentHashMap.newKeySet(); this.delayedRequests = new ConcurrentHashMap<>(); + this.resources = new ConcurrentHashMap<>(); this.delayedRequestsId = ConcurrentHashMap.newKeySet(); this.profileUuid = profileUuid; /** @@ -102,21 +98,29 @@ public class LwM2MClient implements Cloneable { private void initValue() { this.responses.forEach((key, resp) -> { - LwM2mPath pathIds = new LwM2mPath(key); + LwM2mPath pathIds = new LwM2mPath(key); if (pathIds.isObject() || pathIds.isObjectInstance() || pathIds.isResource()) { ObjectModel objectModel = this.lwServer.getModelProvider().getObjectModel(registration).getObjectModels().stream().filter(v -> v.id == pathIds.getObjectId()).collect(Collectors.toList()).get(0); - if (this.modelObjects.get(pathIds.getObjectId()) != null) { - this.modelObjects.get(pathIds.getObjectId()).getInstances().put(((ReadResponse) resp).getContent().getId(), (LwM2mObjectInstance) ((ReadResponse) resp).getContent()); - } else { - Map instances = new ConcurrentHashMap<>(); - instances.put(((ReadResponse) resp).getContent().getId(), (LwM2mObjectInstance) ((ReadResponse) resp).getContent()); - ModelObject modelObject = new ModelObject(objectModel, instances); - this.modelObjects.put(pathIds.getObjectId(), modelObject); + if (objectModel != null) { + ((LwM2mObjectInstance)((ReadResponse)resp).getContent()).getResources().forEach((k, v) -> { + String rez = pathIds.toString() + "/" + k; + boolean ismulti = objectModel.resources.get(k).multiple; + if (objectModel.resources.get(k).multiple){ + this.resources.put(rez, new ResourceValue(v.getValues(), null, true)); + } + else { + this.resources.put(rez, new ResourceValue(null, v.getValue(), false)); + } + }); } } }); } + /** + * if path != null + * @param path + */ public void onSuccessOrErrorDelayedRequests(String path) { if (path != null) this.delayedRequests.remove(path); if (this.delayedRequests.size() == 0 && this.getDelayedRequestsId().size() == 0) { @@ -124,43 +128,5 @@ public class LwM2MClient implements Cloneable { } } - public ResourceModel.Operations getOperation(String path) { - LwM2mPath resultIds = new LwM2mPath(path); - return (this.getModelObjects().get(resultIds.getObjectId()) != null) ? - this.getModelObjects().get(resultIds.getObjectId()).getObjectModel().resources.get(resultIds.getResourceId()).operations : - ResourceModel.Operations.NONE; - } - - public String getResourceName(String path) { - LwM2mPath resultIds = new LwM2mPath(path); - return (this.getModelObjects().get(resultIds.getObjectId()) != null) ? this.getModelObjects().get(resultIds.getObjectId()).getObjectModel().resources.get(resultIds.getResourceId()).name : ""; - } - - /** - * @param path - path resource - * @return - value of Resource or null - */ - public String getResourceValue(String path) { - String resValue = null; - LwM2mPath pathIds = new LwM2mPath(path); - ModelObject modelObject = this.getModelObjects().get(pathIds.getObjectId()); - - if (modelObject != null && modelObject.getInstances().get(pathIds.getObjectInstanceId()) != null) { - LwM2mObjectInstance instance = modelObject.getInstances().get(pathIds.getObjectInstanceId()); - if (instance.getResource(pathIds.getResourceId()) != null) { - try { - resValue = instance.getResource(pathIds.getResourceId()).getType() == OPAQUE ? - Hex.encodeHexString((byte[]) instance.getResource(pathIds.getResourceId()).getValue()).toLowerCase() : - (instance.getResource(pathIds.getResourceId()).isMultiInstances()) ? - instance.getResource(pathIds.getResourceId()).getValues().toString() : -// getValueTypeToString(instance.getResource(pathIds.getResourceId()).getValue(), instance.getResource(pathIds.getResourceId()).getType()); - (String) converter.convertValue(instance.getResource(pathIds.getResourceId()).getValue(), instance.getResource(pathIds.getResourceId()).getType(), ResourceModel.Type.STRING, pathIds); - } catch (Exception e) { - log.warn("getResourceValue [{}]", e.getStackTrace().toString()); - } - } - } - return resValue; - } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResourceValue.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResourceValue.java index 312973b9d0..d58890dfba 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResourceValue.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResourceValue.java @@ -23,4 +23,14 @@ public class ResourceValue { Map values; Object value; boolean multiInstances; + + public ResourceValue ( Map values, Object value, boolean multiInstances) { + this.values = values; + this.value = value; + this.multiInstances = multiInstances; + } + public Object getResourceValue() { + return this.multiInstances ? this.values : this.value; + } + } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java index 07294bccfe..216136be8b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java @@ -179,11 +179,13 @@ public class LwM2mInMemorySecurityStore extends InMemorySecurityStore { if (store.getSecurityInfo() != null) { if (store.getSecurityMode() < DEFAULT_MODE.code) { String endpoint = store.getSecurityInfo().getEndpoint(); - sessions.put(endpoint, new LwM2MClient(endpoint, store.getSecurityInfo().getIdentity(), store.getSecurityInfo(), store.getMsg(), null, null, profileUuid)); +// sessions.put(endpoint, new LwM2MClient(endpoint, store.getSecurityInfo().getIdentity(), store.getSecurityInfo(), store.getMsg(), null, null, profileUuid)); + sessions.put(endpoint, new LwM2MClient(endpoint, store.getSecurityInfo().getIdentity(), store.getSecurityInfo(), store.getMsg(), null, profileUuid)); } } else { if (store.getSecurityMode() == NO_SEC.code && profileUuid != null) - sessions.put(identity, new LwM2MClient(identity, null, null, store.getMsg(), null, null, profileUuid)); +// sessions.put(identity, new LwM2MClient(identity, null, null, store.getMsg(), null, null, profileUuid)); + sessions.put(identity, new LwM2MClient(identity, null, null, store.getMsg(), null, profileUuid)); else { log.error("Registration failed: FORBIDDEN/profileUuid/device [{}] , endpointId: [{}]", profileUuid, identity); /** diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java index d7cae734a2..44fcfad9b6 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java @@ -26,6 +26,8 @@ import org.eclipse.leshan.core.util.StringUtils; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.XMLGregorianCalendar; +import java.text.DateFormat; +import java.text.SimpleDateFormat; import java.util.Date; @Slf4j @@ -120,6 +122,12 @@ public class LwM2mValueConverterImpl implements LwM2mValueConverter { case INTEGER: case FLOAT: return String.valueOf(value); + case TIME: +// return Long.toString(((Date) value).getTime()); + String DATE_FORMAT = "MMM d, yyyy HH:mm a"; + Long timeValue = ((Date) value).getTime(); + DateFormat formatter = new SimpleDateFormat(DATE_FORMAT); + return formatter.format(new Date(timeValue)); default: break; } diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigServer.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigServer.java index d8f305a049..89c1600bf5 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigServer.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigServer.java @@ -20,6 +20,8 @@ import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.model.ObjectLoader; import org.eclipse.leshan.core.model.ObjectModel; +import org.eclipse.leshan.core.model.ResourceModel; +import org.eclipse.leshan.core.node.LwM2mPath; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Component; @@ -33,6 +35,8 @@ import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; @Slf4j @Component @@ -173,6 +177,10 @@ public class LwM2MTransportConfigServer { @Value("${transport.lwm2m.secure.redis_url:}") private String redisUrl; + @Getter + @Setter + private Map objectModels; + @PostConstruct public void init() { modelsValue = ObjectLoader.loadDefault(); @@ -188,6 +196,7 @@ public class LwM2MTransportConfigServer { log.error(" [{}] Read Models", path.getAbsoluteFile()); } getInKeyStore(); + this.objectModels = new ConcurrentHashMap(); } private File getPathModels() { @@ -238,4 +247,22 @@ public class LwM2MTransportConfigServer { } return FULL_FILE_PATH.toUri().getPath(); } + + public ResourceModel getResourceModel(LwM2mPath pathIds) { + return (this.objectModels.size()>0 && + this.objectModels.containsKey(pathIds.getObjectId()) && + this.objectModels.get(pathIds.getObjectId()).resources.containsKey(pathIds.getResourceId())) ? + this.objectModels.get(pathIds.getObjectId()).resources.get(pathIds.getResourceId()) : null; + } + + public ResourceModel.Type getResourceModelType(LwM2mPath pathIds) { + ResourceModel resource = this.getResourceModel(pathIds); + return (resource == null) ? null : resource.type; + } + + public ResourceModel.Operations getOperation(LwM2mPath pathIds) { + ResourceModel resource = this.getResourceModel(pathIds); + return (resource == null) ? ResourceModel.Operations.NONE : resource.operations; + } + } From 4f3707c1e115afe5167c76987a30c415cc91d87f Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 29 Dec 2020 14:26:39 +0200 Subject: [PATCH 014/249] Lwm2m: backEnd: add PUT_TYPE_OPER_WRITE_UPDATE --- .../lwm2m/server/LwM2MTransportHandler.java | 30 ++----------------- .../lwm2m/server/LwM2MTransportRequest.java | 5 ++-- .../lwm2m/server/LwM2MTransportService.java | 7 ----- 3 files changed, 5 insertions(+), 37 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportHandler.java index 1e84af7d48..14d06eb7e6 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportHandler.java @@ -99,11 +99,13 @@ public class LwM2MTransportHandler { /** * Replaces the Object Instance or the Resource(s) with the new value provided in the “Write” operation. (see * section 5.3.3 of the LW M2M spec). + * if all resources are to be replaced */ public static final String POST_TYPE_OPER_WRITE_REPLACE = "replace"; /** * Adds or updates Resources provided in the new value and leaves other existing Resources unchanged. (see section * 5.3.3 of the LW M2M spec). + * if this is a partial update request */ public static final String PUT_TYPE_OPER_WRITE_UPDATE = "update"; public static final String PUT_TYPE_OPER_WRITE_ATTRIBUTES = "wright-attributes"; @@ -152,34 +154,6 @@ public class LwM2MTransportHandler { return coapConfig; } -// public static String getValueTypeToString (Object value, ResourceModel.Type type, int val) { -// try{ -// switch (type) { -// case STRING: // String -// case OBJLNK: // ObjectLink -// return value.toString(); -// case INTEGER: // Long -// return Long.toString((long) value); -// case BOOLEAN: // Boolean -// return Boolean.toString((Boolean) value); -// case FLOAT: // Double -// return Double.toString((Double) value); -// case TIME: // Date -// return Long.toString(((Date) value).getTime()); -//// String DATE_FORMAT = "MMM d, yyyy HH:mm a"; -//// DateFormat formatter = new SimpleDateFormat(DATE_FORMAT); -//// return formatter.format(new Date(Integer.toUnsignedLong((Integer) value))); -// case OPAQUE: // byte[] value, base64 -// return Hex.encodeHexString((byte[])value); -// default: -// return null; -// } -// } catch (Exception e) { -// log.error(e.getStackTrace().toString()); -// return null; -// } -// } - public static boolean equalsResourceValue(Object valueOld, Object valueNew, ResourceModel.Type type, LwM2mPath resourcePath) throws CodecException { switch (type) { case BOOLEAN: diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java index f0b96d0225..e34cfdd34e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java @@ -20,6 +20,7 @@ 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; import org.eclipse.leshan.core.node.LwM2mSingleResource; import org.eclipse.leshan.core.node.ObjectLink; @@ -146,7 +147,6 @@ public class LwM2MTransportRequest { break; case POST_TYPE_OPER_EXECUTE: if (params != null && resource != null && !resource.multiple) { -// request = new ExecuteRequest(target, LwM2MTransportHandler.getValueTypeToString(params, resType)); request = new ExecuteRequest(target, (String) this.converter.convertValue(params, resource.type, ResourceModel.Type.STRING, resultIds)); } else { request = new ExecuteRequest(target); @@ -168,7 +168,8 @@ public class LwM2MTransportRequest { if (resultIds.getResourceId() >= 0) { ResourceModel resourceModel = lwServer.getModelProvider().getObjectModel(registration).getObjectModel(resultIds.getObjectId()).resources.get(resultIds.getResourceId()); ResourceModel.Type typeRes = resourceModel.type; -// request = getWriteRequestResource(resultIds.getObjectId(), resultIds.getInstanceId(), resultIds.getResourceId(), params, typeRes); + LwM2mNode node = LwM2mSingleResource.newStringResource(resultIds.getResourceId(), (String) this.converter.convertValue(params, resource.type, ResourceModel.Type.STRING, resultIds)); + request = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, target, node); } break; case PUT_TYPE_OPER_WRITE_ATTRIBUTES: diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java index 5e4d4198f0..9c953f4069 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java @@ -515,7 +515,6 @@ public class LwM2MTransportService { private void getParametersFromProfile(JsonObject attributes, JsonObject telemetry, Registration registration, Set path) { AttrTelemetryObserveValue attrTelemetryObserveValue = lwM2mInMemorySecurityStore.getProfiles().get(lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getProfileUuid()); attrTelemetryObserveValue.getPostAttributeProfile().forEach(p -> { -// ResultIds pathIds = new ResultIds(p.getAsString().toString()); LwM2mPath pathIds = new LwM2mPath(p.getAsString().toString()); if (pathIds.isResource()) { if (path == null || path.contains(p.getAsString())) { @@ -524,7 +523,6 @@ public class LwM2MTransportService { } }); attrTelemetryObserveValue.getPostTelemetryProfile().forEach(p -> { -// ResultIds pathIds = new ResultIds(p.getAsString().toString()); LwM2mPath pathIds = new LwM2mPath(p.getAsString().toString()); if (pathIds.isResource()) { if (path == null || path.contains(p.getAsString())) { @@ -545,10 +543,8 @@ public class LwM2MTransportService { if (resName != null && !resName.isEmpty()) { String resValue = null; try { -// resValue = lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getResourceValueString(path); resValue = this.getResourceValueToString(lwM2MClient, path); if (resValue != null) { -// log.info("addParameters Path: [{}] ResValue : [{}] nameParam [{}]", path, lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getResourceValue(path), nameParam); parameters.addProperty(resName, resValue); } } catch (Exception e) { @@ -1061,10 +1057,7 @@ public class LwM2MTransportService { */ private void updateResourceValueObserve(LeshanServer lwServer, Registration registration, LwM2MClient lwM2MClient, Set targets, String typeOper) { targets.forEach(target -> { -// ResultIds pathIds = new ResultIds(target); LwM2mPath pathIds = new LwM2mPath(target); -// if (pathIds.isResource() && lwM2MClient.getModelObjects().get(pathIds.getObjectId()) -// .getInstances().get(pathIds.getObjectInstanceId()).getResource(pathIds.getResourceId()).getValue() != null) { if (pathIds.isResource()) { if (GET_TYPE_OPER_READ.equals(typeOper)) { lwM2MTransportRequest.sendAllRequest(lwServer, registration, target, typeOper, From 02615cb93dd57c366a54f6cb5076864e2f64981d Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 29 Dec 2020 15:24:57 +0200 Subject: [PATCH 015/249] Lwm2m: backEnd: add to updateReg new registerAsyncSession --- .../src/main/resources/thingsboard.yml | 2 +- .../lwm2m/server/LwM2MTransportService.java | 23 ++++++++++++++----- .../common/transport/TransportService.java | 4 ++-- .../service/DefaultTransportService.java | 4 ++-- .../transport/service/SessionMetaData.java | 1 + 5 files changed, 23 insertions(+), 11 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index b5fe6b29cb..065a0a4cb0 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -433,7 +433,7 @@ spring: database-platform: "${SPRING_JPA_DATABASE_PLATFORM:org.hibernate.dialect.PostgreSQLDialect}" datasource: driverClassName: "${SPRING_DRIVER_CLASS_NAME:org.postgresql.Driver}" - url: "${SPRING_DATASOURCE_URL:jdbc:postgresql://localhost:5432/thingsboard_ce_3_3_test}" + url: "${SPRING_DATASOURCE_URL:jdbc:postgresql://localhost:5432/thingsboard}" username: "${SPRING_DATASOURCE_USERNAME:postgres}" password: "${SPRING_DATASOURCE_PASSWORD:postgres}" hikari: diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java index 9c953f4069..ac2059b561 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java @@ -177,6 +177,7 @@ public class LwM2MTransportService { } /** + * if sessionInfo removed from sessions, then new registerAsyncSession * @param lwServer - LeshanServer * @param registration - Registration LwM2M Client */ @@ -185,8 +186,7 @@ public class LwM2MTransportService { try { SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration.getId()); if (sessionInfo != null) { -// transportService.reportActivity(sessionInfo); -// transportService.registerAsyncSession(sessionInfo, new LwM2MSessionMsgListener(this, sessionInfo)); + this.checkInactivity(sessionInfo); log.info("Client: [{}] updatedReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType()); } else { log.error("Client: [{}] updatedReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); @@ -197,6 +197,7 @@ public class LwM2MTransportService { }); } + /** * @param registration - Registration LwM2M Client * @param observations - All paths observations before unReg @@ -691,11 +692,11 @@ public class LwM2MTransportService { ResourceValue resValueOld = lwM2MClient.getResources().get(path); // #2 if (resValueOld.isMultiInstances() && !values.toString().equals(resValueOld.getResourceValue().toString())) { - ResourceValue resourceValue = new ResourceValue ( values, null, true); + ResourceValue resourceValue = new ResourceValue(values, null, true); lwM2MClient.getResources().put(path, resourceValue); isChange = true; } else if (!LwM2MTransportHandler.equalsResourceValue(resValueOld.getValue(), value, resModelType, pathIds)) { - ResourceValue resourceValue = new ResourceValue ( null, value, false); + ResourceValue resourceValue = new ResourceValue(null, value, false); lwM2MClient.getResources().put(path, resourceValue); isChange = true; } @@ -739,7 +740,7 @@ public class LwM2MTransportService { String value = de.getValue().getAsString(); LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getSession(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())).entrySet().iterator().next().getValue(); AttrTelemetryObserveValue profile = lwM2mInMemorySecurityStore.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); - ResourceModel resourceModel = context.getCtxServer().getResourceModel(new LwM2mPath(path)); + ResourceModel resourceModel = context.getCtxServer().getResourceModel(new LwM2mPath(path)); if (path != null && (this.validatePathInAttrProfile(profile, path) || this.validatePathInTelemetryProfile(profile, path))) { if (resourceModel != null && resourceModel.operations.isWritable()) { lwM2MTransportRequest.sendAllRequest(lwM2MClient.getLwServer(), lwM2MClient.getRegistration(), path, POST_TYPE_OPER_WRITE_REPLACE, @@ -1125,7 +1126,17 @@ public class LwM2MTransportService { } private void checkInactivityAndReportActivity() { - lwM2mInMemorySecurityStore.getSessions().forEach((key, value) -> transportService.reportActivity(this.getValidateSessionInfo(key))); + lwM2mInMemorySecurityStore.getSessions().forEach((key, value) -> this.checkInactivity(this.getValidateSessionInfo(key))); + } + + /** + * if sessionInfo removed from sessions, then new registerAsyncSession + * @param sessionInfo + */ + private void checkInactivity(SessionInfoProto sessionInfo) { + if (transportService.reportActivity(sessionInfo) == null) { + transportService.registerAsyncSession(sessionInfo, new LwM2MSessionMsgListener(this, sessionInfo)); + } } public void sentLogsToThingsboard(String msg, String registrationId) { diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportService.java index cec9eba5a1..d676874458 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportService.java @@ -19,7 +19,7 @@ import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.transport.auth.GetOrCreateDeviceFromGatewayResponse; import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; -import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.common.transport.service.SessionMetaData; import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg; import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileRequestMsg; @@ -98,7 +98,7 @@ public interface TransportService { void registerSyncSession(SessionInfoProto sessionInfo, SessionMsgListener listener, long timeout); - void reportActivity(SessionInfoProto sessionInfo); + SessionMetaData reportActivity(SessionInfoProto sessionInfo); void deregisterSession(SessionInfoProto sessionInfo); } diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java index 246ad7c7c0..3a4790e58a 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java @@ -509,8 +509,8 @@ public class DefaultTransportService implements TransportService { } @Override - public void reportActivity(TransportProtos.SessionInfoProto sessionInfo) { - reportActivityInternal(sessionInfo); + public SessionMetaData reportActivity(TransportProtos.SessionInfoProto sessionInfo) { + return reportActivityInternal(sessionInfo); } private SessionMetaData reportActivityInternal(TransportProtos.SessionInfoProto sessionInfo) { diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/SessionMetaData.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/SessionMetaData.java index ac293307a9..dba3338d67 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/SessionMetaData.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/SessionMetaData.java @@ -25,6 +25,7 @@ import java.util.concurrent.ScheduledFuture; * Created by ashvayka on 15.10.18. */ @Data +public class SessionMetaData { private volatile TransportProtos.SessionInfoProto sessionInfo; From e91cb65399ebadbdae7389ff30bad50939bd603b Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 29 Dec 2020 19:12:45 +0200 Subject: [PATCH 016/249] Lwm2m: backEnd: fix bug getResourceValueToString NullPointExaption --- .../transport/lwm2m/server/LwM2MTransportRequest.java | 4 ++-- .../transport/lwm2m/server/LwM2MTransportService.java | 7 +++---- .../server/transport/lwm2m/server/client/LwM2MClient.java | 1 - 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java index e34cfdd34e..134c979529 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java @@ -311,7 +311,7 @@ public class LwM2MTransportRequest { try { sendResponse(registration, path, response, request, lwM2MClient, isDelayedUpdate); } catch (Exception e) { - log.error("[{}] endpoint [{}] path [{}] error Unable to after send response.", registration.getEndpoint(), path, e); + log.error("[{}] endpoint [{}] path [{}] Exception Unable to after send response.", registration.getEndpoint(), path, e); } }); } @@ -321,7 +321,7 @@ public class LwM2MTransportRequest { try { if (isDelayedUpdate) lwM2MClient.onSuccessOrErrorDelayedRequests(path); } catch (RuntimeException t) { - log.error("[{}] endpoint [{}] path [{}] error Unable to after send response.", registration.getEndpoint(), path, t.toString()); + log.error("[{}] endpoint [{}] path [{}] RuntimeException Unable to after send response.", registration.getEndpoint(), path, t); } }); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java index ac2059b561..ba3cd1f736 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java @@ -415,7 +415,6 @@ public class LwM2MTransportService { List listV = new ArrayList(); listV.add(v.getKv()); this.putDelayedUpdateResourcesClient(lwM2MClient, this.getResourceValueToString(lwM2MClient, k), getJsonObject(listV).get(v.getKv().getKey()), k); - System.out.printf(" k: %s, v: %s%n, v1: %s%n", k, v.getKv().getStringV(), this.getResourceValueToString(lwM2MClient, k)); }); lwM2MClient.getDelayedRequestsId().remove(attributesResponse.getRequestId()); if (lwM2MClient.getDelayedRequests().size() == 0) { @@ -425,7 +424,7 @@ public class LwM2MTransportService { } private void putDelayedUpdateResourcesClient(LwM2MClient lwM2MClient, Object valueOld, Object valueNew, String path) { - if (!valueOld.toString().equals(valueNew.toString())) { + if (valueNew != null && !valueNew.toString().equals(valueOld.toString())) { lwM2MTransportRequest.sendAllRequest(lwM2MClient.getLwServer(), lwM2MClient.getRegistration(), path, POST_TYPE_OPER_WRITE_REPLACE, ContentFormat.TLV.getName(), lwM2MClient, null, valueNew, this.context.getCtxServer().getTimeout(), true); @@ -1160,7 +1159,7 @@ public class LwM2MTransportService { public String getResourceValueToString(LwM2MClient lwM2MClient, String path) { LwM2mPath pathIds = new LwM2mPath(path); ResourceValue resourceValue = this.getResourceValue(lwM2MClient, pathIds); - return (String) this.converter.convertValue(resourceValue.getResourceValue(), this.context.getCtxServer().getResourceModelType(pathIds), ResourceModel.Type.STRING, pathIds); + return (resourceValue == null) ? null : + (String) this.converter.convertValue(resourceValue.getResourceValue(), this.context.getCtxServer().getResourceModelType(pathIds), ResourceModel.Type.STRING, pathIds); } - } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java index 89ef741da9..e91f8479e2 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java @@ -104,7 +104,6 @@ public class LwM2MClient implements Cloneable { if (objectModel != null) { ((LwM2mObjectInstance)((ReadResponse)resp).getContent()).getResources().forEach((k, v) -> { String rez = pathIds.toString() + "/" + k; - boolean ismulti = objectModel.resources.get(k).multiple; if (objectModel.resources.get(k).multiple){ this.resources.put(rez, new ResourceValue(v.getValues(), null, true)); } From 3a7101a8a356cb67756d8ca31ce45d0a1658821a Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 30 Dec 2020 15:55:57 +0200 Subject: [PATCH 017/249] Lwm2m: backEnd: model Client from provide --- common/transport/lwm2m/pom.xml | 15 +- .../lwm2m/server/LwM2MTransportRequest.java | 12 +- .../lwm2m/server/LwM2MTransportService.java | 183 +++++++----------- .../secure/LwM2mInMemorySecurityStore.java | 8 +- common/transport/transport-api/pom.xml | 5 +- .../lwm2m/LwM2MTransportConfigServer.java | 37 ++-- pom.xml | 25 +++ transport/lwm2m/pom.xml | 4 - 8 files changed, 135 insertions(+), 154 deletions(-) diff --git a/common/transport/lwm2m/pom.xml b/common/transport/lwm2m/pom.xml index a904d1e12f..d23f8dbc5d 100644 --- a/common/transport/lwm2m/pom.xml +++ b/common/transport/lwm2m/pom.xml @@ -65,15 +65,10 @@ ch.qos.logback logback-classic - org.eclipse.leshan leshan-server-cf - - - - org.eclipse.leshan leshan-client-cf @@ -83,12 +78,6 @@ org.eclipse.leshan leshan-server-redis - - - - - - org.springframework.boot spring-boot-starter-test @@ -107,14 +96,12 @@ org.eclipse.californium californium-core - ${californium.version} - test-jar + test-jar test org.eclipse.californium element-connector - ${californium.version} test-jar test diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java index 134c979529..e919835a1a 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java @@ -124,7 +124,7 @@ public class LwM2MTransportRequest { if (registration != null && resultIds.getObjectId() >= 0) { DownlinkRequest request = null; ContentFormat contentFormat = contentFormatParam != null ? ContentFormat.fromName(contentFormatParam.toUpperCase()) : null; - ResourceModel resource = service.context.getCtxServer().getResourceModel(resultIds); + ResourceModel resource = service.context.getCtxServer().getResourceModel(registration, resultIds); timeoutInMs = timeoutInMs > 0 ? timeoutInMs : DEFAULT_TIMEOUT; switch (typeOper) { case GET_TYPE_OPER_READ: @@ -222,7 +222,7 @@ public class LwM2MTransportRequest { this.sendRequest(lwServer, registration, request, lwM2MClient, timeoutInMs, isDelayedUpdate); } else if (request == null && isDelayedUpdate) { String msg = String.format(LOG_LW2M_ERROR + ": sendRequest: Resource path - %s msg No SendRequest to Client", target); - service.sentLogsToThingsboard(msg, registration.getId()); + service.sentLogsToThingsboard(msg, registration); log.error("[{}] - [{}] No SendRequest", target); this.handleResponseError(registration, target, lwM2MClient, isDelayedUpdate); @@ -251,14 +251,14 @@ public class LwM2MTransportRequest { String msg = String.format(LOG_LW2M_INFO + ": sendRequest Replace%s: CoapCde - %s Lwm2m code - %d name - %s Resource path - %s value - %s SendRequest to Client", delayedUpdateStr, ((Response) response.getCoapResponse()).getCode(), response.getCode().getCode(), response.getCode().getName(), request.getPath().toString(), ((LwM2mSingleResource) ((WriteRequest) request).getNode()).getValue().toString()); - service.sentLogsToThingsboard(msg, registration.getId()); + service.sentLogsToThingsboard(msg, registration); log.info("[{}] - [{}] [{}] [{}] Update SendRequest[{}]", ((Response) response.getCoapResponse()).getCode(), response.getCode(), request.getPath().toString(), ((LwM2mSingleResource) ((WriteRequest) request).getNode()).getValue(), delayedUpdateStr); } } else { String msg = String.format(LOG_LW2M_ERROR + ": sendRequest: CoapCode - %s Lwm2m code - %d name - %s Resource path - %s SendRequest to Client", ((Response) response.getCoapResponse()).getCode(), response.getCode().getCode(), response.getCode().getName(), request.getPath().toString()); - service.sentLogsToThingsboard(msg, registration.getId()); + service.sentLogsToThingsboard(msg, registration); log.error("[{}] - [{}] [{}] error SendRequest", ((Response) response.getCoapResponse()).getCode(), response.getCode(), request.getPath().toString()); if (request instanceof WriteRequest && ((WriteRequest) request).isReplaceRequest() && isDelayedUpdate) { this.handleResponseError(registration, request.getPath().toString(), lwM2MClient, isDelayedUpdate); @@ -268,7 +268,7 @@ public class LwM2MTransportRequest { }, e -> { String msg = String.format(LOG_LW2M_ERROR + ": sendRequest: Resource path - %s msg error - %s SendRequest to Client", request.getPath().toString(), e.toString()); - service.sentLogsToThingsboard(msg, registration.getId()); + service.sentLogsToThingsboard(msg, registration); log.error("[{}] - [{}] error SendRequest", request.getPath().toString(), e.toString()); if (request instanceof WriteRequest && ((WriteRequest) request).isReplaceRequest() && isDelayedUpdate) { this.handleResponseError(registration, request.getPath().toString(), lwM2MClient, isDelayedUpdate); @@ -300,7 +300,7 @@ public class LwM2MTransportRequest { String patn = "/" + objectId + "/" + instanceId + "/" + resourceId; String msg = String.format(LOG_LW2M_ERROR + ": NumberFormatException: Resource path - %s type - %s value - %s msg error - %s SendRequest to Client", patn, type, value, e.toString()); - service.sentLogsToThingsboard(msg, registration.getId()); + service.sentLogsToThingsboard(msg, registration); log.error("Path: [{}] type: [{}] value: [{}] errorMsg: [{}]]", patn, type, value, e.toString()); return null; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java index ba3cd1f736..d031e63c89 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java @@ -20,13 +20,11 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; 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.LwM2mMultipleResource; 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.LwM2mResource; import org.eclipse.leshan.core.node.LwM2mSingleResource; import org.eclipse.leshan.core.observation.Observation; import org.eclipse.leshan.core.request.ContentFormat; @@ -51,7 +49,6 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToTransportUpdateCre import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; import org.thingsboard.server.transport.lwm2m.server.client.AttrTelemetryObserveValue; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; -import org.thingsboard.server.transport.lwm2m.server.client.ModelObject; import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue; import org.thingsboard.server.transport.lwm2m.server.client.ResultsAnalyzerParameters; import org.thingsboard.server.transport.lwm2m.server.secure.LwM2mInMemorySecurityStore; @@ -62,9 +59,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; -import java.util.NoSuchElementException; import java.util.Optional; import java.util.Random; import java.util.Set; @@ -76,7 +73,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Predicate; import java.util.stream.Collectors; import static org.thingsboard.server.common.transport.util.JsonUtils.getJsonObject; @@ -148,13 +144,14 @@ public class LwM2MTransportService { public void onRegistered(LeshanServer lwServer, Registration registration, Collection previousObsersations) { executorRegistered.submit(() -> { try { - log.info("[{}] Client: onRegistered name ", registration.getEndpoint()); + log.info("[{}] [{{}] Client: create after Registration", registration.getEndpoint(), registration.getId()); LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.updateInSessionsLwM2MClient(lwServer, registration); if (lwM2MClient != null) { lwM2MClient.setLwM2MTransportService(this); lwM2MClient.setSessionUuid(UUID.randomUUID()); + this.sentLogsToThingsboard(LOG_LW2M_INFO + ": Client Registered", registration); this.setLwM2MClient(lwServer, registration, lwM2MClient); - SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration.getId()); + SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration); if (sessionInfo != null) { lwM2MClient.setDeviceUuid(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB())); lwM2MClient.setProfileUuid(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); @@ -163,7 +160,7 @@ public class LwM2MTransportService { transportService.registerAsyncSession(sessionInfo, new LwM2MSessionMsgListener(this, sessionInfo)); transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN), null); transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), null); - this.sentLogsToThingsboard(LOG_LW2M_INFO + ": Client registration", registration.getId()); + this.sentLogsToThingsboard(LOG_LW2M_INFO + ": Client create after Registration", registration); } else { log.error("Client: [{}] onRegistered [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); } @@ -184,7 +181,7 @@ public class LwM2MTransportService { public void updatedReg(LeshanServer lwServer, Registration registration) { executorUpdateRegistered.submit(() -> { try { - SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration.getId()); + SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration); if (sessionInfo != null) { this.checkInactivity(sessionInfo); log.info("Client: [{}] updatedReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType()); @@ -206,7 +203,7 @@ public class LwM2MTransportService { public void unReg(Registration registration, Collection observations) { executorUnRegistered.submit(() -> { try { - this.sentLogsToThingsboard(LOG_LW2M_INFO + ": Client unRegistration", registration.getId()); + this.sentLogsToThingsboard(LOG_LW2M_INFO + ": Client unRegistration", registration); this.closeClientSession(registration); } catch (Throwable t) { log.error("[{}] endpoint [{}] error Unable un registration.", registration.getEndpoint(), t); @@ -215,7 +212,7 @@ public class LwM2MTransportService { } private void closeClientSession(Registration registration) { - SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration.getId()); + SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration); if (sessionInfo != null) { transportService.deregisterSession(sessionInfo); this.doCloseSession(sessionInfo); @@ -278,9 +275,6 @@ public class LwM2MTransportService { * @param lwM2MClient - object with All parameters off client */ private void setLwM2MClient(LeshanServer lwServer, Registration registration, LwM2MClient lwM2MClient) { - // #0 - this.setNewObjectModels(lwServer, registration); - // #1 Arrays.stream(registration.getObjectLinks()).forEach(url -> { LwM2mPath pathIds = new LwM2mPath(url.getUrl()); if (pathIds.isObjectInstance() && !pathIds.isResource()) { @@ -297,30 +291,35 @@ public class LwM2MTransportService { }); } - private void setNewObjectModels(LeshanServer lwServer, Registration registration) { - Arrays.stream(registration.getObjectLinks()).forEach(url -> { - LwM2mPath pathIds = new LwM2mPath(url.getUrl()); - if (pathIds.isObjectInstance() && !pathIds.isResource() && !context.getCtxServer().getObjectModels().containsKey(pathIds.getObjectId())) { - ObjectModel model = lwServer.getModelProvider().getObjectModel(registration).getObjectModels().stream().filter(v -> v.id == pathIds.getObjectId()).collect(Collectors.toList()).get(0); - context.getCtxServer().getObjectModels().put(pathIds.getObjectId(), model); - } - }); + /** + * @param registration - Registration LwM2M Client + * @return - sessionInfo after access connect client + */ + private SessionInfoProto getValidateSessionInfo(Registration registration) { + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClientWithReg(registration, null); + return getNewSessionInfoProto(lwM2MClient); + } /** - * @param registrationId - Id of Registration LwM2M Client - * @return - sessionInfo after access connect client + * + * @param registrationId - + * @return - */ private SessionInfoProto getValidateSessionInfo(String registrationId) { - SessionInfoProto sessionInfo = null; - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(registrationId); + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClientWithReg(null, registrationId); + return getNewSessionInfoProto(lwM2MClient); + } + + private SessionInfoProto getNewSessionInfoProto(LwM2MClient lwM2MClient) { if (lwM2MClient != null) { ValidateDeviceCredentialsResponseMsg msg = lwM2MClient.getCredentialsResponse(); if (msg == null || msg.getDeviceInfo() == null) { log.error("[{}] [{}]", lwM2MClient.getEndPoint(), CLIENT_NOT_AUTHORIZED); this.closeClientSession(lwM2MClient.getRegistration()); + return null; } else { - sessionInfo = SessionInfoProto.newBuilder() + return SessionInfoProto.newBuilder() .setNodeId(this.context.getNodeId()) .setSessionIdMSB(lwM2MClient.getSessionUuid().getMostSignificantBits()) .setSessionIdLSB(lwM2MClient.getSessionUuid().getLeastSignificantBits()) @@ -335,7 +334,7 @@ public class LwM2MTransportService { .build(); } } - return sessionInfo; + return null; } /** @@ -365,7 +364,7 @@ public class LwM2MTransportService { * @param lwM2MClient - LwM2M Client */ public void putDelayedUpdateResourcesThingsboard(LwM2MClient lwM2MClient) { - SessionInfoProto sessionInfo = this.getValidateSessionInfo(lwM2MClient.getRegistration().getId()); + SessionInfoProto sessionInfo = this.getValidateSessionInfo(lwM2MClient.getRegistration()); if (sessionInfo != null) { //#1.1 + #1.2 List attrSharedNames = this.getNamesAttrFromProfileIsWritable(lwM2MClient); @@ -404,7 +403,7 @@ public class LwM2MTransportService { attributesResponse.getSharedAttributeListList().forEach(attr -> { String path = this.getPathAttributeUpdate(sessionInfo, attr.getKv().getKey()); // #1.1 - if (lwM2MClient.getDelayedRequests().keySet().contains(path) && attr.getTs() > lwM2MClient.getDelayedRequests().get(path).getTs()) { + if (lwM2MClient.getDelayedRequests().containsKey(path) && attr.getTs() > lwM2MClient.getDelayedRequests().get(path).getTs()) { lwM2MClient.getDelayedRequests().put(path, attr); } else { lwM2MClient.getDelayedRequests().put(path, attr); @@ -412,7 +411,7 @@ public class LwM2MTransportService { }); // #2.1 lwM2MClient.getDelayedRequests().forEach((k, v) -> { - List listV = new ArrayList(); + ArrayList listV = new ArrayList<>(); listV.add(v.getKv()); this.putDelayedUpdateResourcesClient(lwM2MClient, this.getResourceValueToString(lwM2MClient, k), getJsonObject(listV).get(v.getKv().getKey()), k); }); @@ -432,24 +431,24 @@ public class LwM2MTransportService { } /** - * Get names and keyNames from profile attr resources IsWritable - * + * Get names and keyNames from profile shared!!!! attr resources IsWritable * @param lwM2MClient - - * @return ArrayList names and keyNames from profile attr resources IsWritable + * @return ArrayList keyNames from profile attr resources shared!!!! && IsWritable */ private List getNamesAttrFromProfileIsWritable(LwM2MClient lwM2MClient) { - Set namesIsIsWritable = ConcurrentHashMap.newKeySet(); AttrTelemetryObserveValue profile = lwM2mInMemorySecurityStore.getProfile(lwM2MClient.getProfileUuid()); Set attrSet = new Gson().fromJson(profile.getPostAttributeProfile(), Set.class); ConcurrentMap keyNamesMap = new Gson().fromJson(profile.getPostKeyNameProfile().toString(), ConcurrentHashMap.class); + ConcurrentMap keyNamesIsWritable = keyNamesMap.entrySet() .stream() - .filter(e -> (attrSet.contains(e.getKey()) && context.getCtxServer().getResourceModel(new LwM2mPath(e.getKey())) != null && - context.getCtxServer().getResourceModel(new LwM2mPath(e.getKey())).operations.isWritable())) + .filter(e -> (attrSet.contains(e.getKey()) && context.getCtxServer().getResourceModel(lwM2MClient.getRegistration(), new LwM2mPath(e.getKey())) != null && + context.getCtxServer().getResourceModel(lwM2MClient.getRegistration(), new LwM2mPath(e.getKey())).operations.isWritable())) .collect(Collectors.toConcurrentMap(Map.Entry::getKey, Map.Entry::getValue)); - namesIsIsWritable.addAll(new HashSet<>(keyNamesIsWritable.values())); - keyNamesIsWritable.keySet().forEach(p -> namesIsIsWritable.add(this.getResourceName(p))); - return new ArrayList<>(namesIsIsWritable); + + Set namesIsWritable = ConcurrentHashMap.newKeySet(); + namesIsWritable.addAll(new HashSet<>(keyNamesIsWritable.values())); + return new ArrayList<>(namesIsWritable); } @@ -484,9 +483,9 @@ public class LwM2MTransportService { log.error("[{}] updateAttrTelemetry", e.toString()); } if (attributes.getAsJsonObject().entrySet().size() > 0) - this.updateParametersOnThingsboard(attributes, DEVICE_ATTRIBUTES_TOPIC, registration.getId()); + this.updateParametersOnThingsboard(attributes, DEVICE_ATTRIBUTES_TOPIC, registration); if (telemetries.getAsJsonObject().entrySet().size() > 0) - this.updateParametersOnThingsboard(telemetries, DEVICE_TELEMETRY_TOPIC, registration.getId()); + this.updateParametersOnThingsboard(telemetries, DEVICE_TELEMETRY_TOPIC, registration); } /** @@ -541,9 +540,8 @@ public class LwM2MTransportService { JsonObject names = lwM2mInMemorySecurityStore.getProfiles().get(lwM2MClient.getProfileUuid()).getPostKeyNameProfile(); String resName = String.valueOf(names.get(path)); if (resName != null && !resName.isEmpty()) { - String resValue = null; try { - resValue = this.getResourceValueToString(lwM2MClient, path); + String resValue = this.getResourceValueToString(lwM2MClient, path); if (resValue != null) { parameters.addProperty(resName, resValue); } @@ -558,14 +556,14 @@ public class LwM2MTransportService { * * @param msg - JsonArray: [{name: value}] * @param topicName - Api Attribute or Telemetry - * @param registrationId - Id of Registration LwM2M Client + * @param registration - Id of Registration LwM2M Client */ - public void updateParametersOnThingsboard(JsonElement msg, String topicName, String registrationId) { - SessionInfoProto sessionInfo = this.getValidateSessionInfo(registrationId); + public void updateParametersOnThingsboard(JsonElement msg, String topicName, Registration registration) { + SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration); if (sessionInfo != null) { context.sentParametersOnThingsboard(msg, topicName, sessionInfo); } else { - log.error("Client: [{}] updateParametersOnThingsboard [{}] sessionInfo ", registrationId, null); + log.error("Client: [{}] updateParametersOnThingsboard [{}] sessionInfo ", registration, null); } } @@ -655,10 +653,9 @@ public class LwM2MTransportService { public void onObservationResponse(Registration registration, String path, ReadResponse response) { if (response.getContent() != null) { if (response.getContent() instanceof LwM2mObject) { - LwM2mObject content = (LwM2mObject) response.getContent(); - String target = "/" + content.getId(); +// LwM2mObject content = (LwM2mObject) response.getContent(); } else if (response.getContent() instanceof LwM2mObjectInstance) { - LwM2mObjectInstance content = (LwM2mObjectInstance) response.getContent(); +// LwM2mObjectInstance content = (LwM2mObjectInstance) response.getContent(); } else if (response.getContent() instanceof LwM2mSingleResource) { LwM2mSingleResource content = (LwM2mSingleResource) response.getContent(); this.onObservationSetResourcesValue(registration, content.getValue(), null, path); @@ -684,10 +681,10 @@ public class LwM2MTransportService { boolean isChange = false; try { // #1 - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(registration.getId()); + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClientWithReg(registration, null); LwM2mPath pathIds = new LwM2mPath(path); log.warn("#0 nameDevice: [{}] resultIds: [{}] value: [{}], values: [{}] ", lwM2MClient.getDeviceName(), pathIds, value, values); - ResourceModel.Type resModelType = context.getCtxServer().getResourceModelType(pathIds); + ResourceModel.Type resModelType = context.getCtxServer().getResourceModelType(registration, pathIds); ResourceValue resValueOld = lwM2MClient.getResources().get(path); // #2 if (resValueOld.isMultiInstances() && !values.toString().equals(resValueOld.getResourceValue().toString())) { @@ -739,8 +736,8 @@ public class LwM2MTransportService { String value = de.getValue().getAsString(); LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getSession(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())).entrySet().iterator().next().getValue(); AttrTelemetryObserveValue profile = lwM2mInMemorySecurityStore.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); - ResourceModel resourceModel = context.getCtxServer().getResourceModel(new LwM2mPath(path)); - if (path != null && (this.validatePathInAttrProfile(profile, path) || this.validatePathInTelemetryProfile(profile, path))) { + ResourceModel resourceModel = context.getCtxServer().getResourceModel(lwM2MClient.getRegistration(), new LwM2mPath(path)); + if (!path.isEmpty() && (this.validatePathInAttrProfile(profile, path) || this.validatePathInTelemetryProfile(profile, path))) { if (resourceModel != null && resourceModel.operations.isWritable()) { lwM2MTransportRequest.sendAllRequest(lwM2MClient.getLwServer(), lwM2MClient.getRegistration(), path, POST_TYPE_OPER_WRITE_REPLACE, ContentFormat.TLV.getName(), lwM2MClient, null, value, this.context.getCtxServer().getTimeout(), @@ -748,12 +745,12 @@ public class LwM2MTransportService { } else { log.error("Resource path - [{}] value - [{}] is not Writable and cannot be updated", path, value); String logMsg = String.format(LOG_LW2M_ERROR + ": attributeUpdate: Resource path - %s value - %s is not Writable and cannot be updated", path, value); - this.sentLogsToThingsboard(logMsg, lwM2MClient.getRegistration().getId()); + this.sentLogsToThingsboard(logMsg, lwM2MClient.getRegistration()); } } else { log.error("Attribute name - [{}] value - [{}] is not present as attribute in profile and cannot be updated", de.getKey(), value); String logMsg = String.format(LOG_LW2M_ERROR + ": attributeUpdate: attribute name - %s value - %s is not present as attribute in profile and cannot be updated", de.getKey(), value); - this.sentLogsToThingsboard(logMsg, lwM2MClient.getRegistration().getId()); + this.sentLogsToThingsboard(logMsg, lwM2MClient.getRegistration()); } }); } else if (msg.getSharedDeletedCount() > 0) { @@ -767,11 +764,12 @@ public class LwM2MTransportService { * * @param sessionInfo - * @param name - - * @return true if path isPresent in postProfile + * @return path if path isPresent in postProfile */ private String getPathAttributeUpdate(TransportProtos.SessionInfoProto sessionInfo, String name) { String profilePath = this.getPathAttributeUpdateProfile(sessionInfo, name); - return !profilePath.isEmpty() ? profilePath : this.getPathAttributeUpdateModelObject(sessionInfo, name); +// return !profilePath.isEmpty() ? profilePath : this.getPathAttributeUpdateModelObject(name); + return !profilePath.isEmpty() ? profilePath : null; } /** @@ -800,7 +798,7 @@ public class LwM2MTransportService { * * @param sessionInfo - * @param name - - * @return + * @return - */ private String getPathAttributeUpdateProfile(TransportProtos.SessionInfoProto sessionInfo, String name) { AttrTelemetryObserveValue profile = lwM2mInMemorySecurityStore.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); @@ -809,31 +807,6 @@ public class LwM2MTransportService { .orElse(""); } - /** - * Get path to resource from ModelObject equal name - * - * @param name - - * @return true if name isPresent as Resource name (usual format) in ResourceModel - */ - private String getPathAttributeUpdateModelObject(TransportProtos.SessionInfoProto sessionInfo, String name) { - try { - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getSession(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())).entrySet().iterator().next().getValue(); - Predicate> predicateRes = res -> name.equals(res.getValue().name); - Predicate> predicateObj = (obj -> { - return obj.getValue().getObjectModel().resources.entrySet().stream().filter(predicateRes).findFirst().isPresent(); - }); -// Map.Entry object = lwM2MClient.getModelObjects().entrySet().stream().filter(predicateObj).findFirst().get(); - Map.Entry object = null; - ModelObject modelObject = object.getValue(); - LwM2mObjectInstance instance = modelObject.getInstances().entrySet().stream().findFirst().get().getValue(); - ResourceModel resource = modelObject.getObjectModel().resources.entrySet().stream().filter(predicateRes).findFirst().get().getValue(); - return new LwM2mPath(object.getKey(), instance.getId(), resource.id).toString(); - } catch (NoSuchElementException e) { - log.error("[{}] keyName [{}]", name, e.toString()); - return null; - } - } - /** * Update resource (attribute) value on thingsboard after update value in client * @@ -842,17 +815,14 @@ public class LwM2MTransportService { * @param request - */ public void onAttributeUpdateOk(Registration registration, String path, WriteRequest request, boolean isDelayedUpdate) { -// ResultIds resultIds = new ResultIds(path); - LwM2mPath resultIds = new LwM2mPath(path); - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(registration.getId()); -// LwM2mResource resource = lwM2MClient.getModelObjects().get(resultIds.getObjectId()).getInstances().get(resultIds.getObjectInstanceId()).getResource(resultIds.getResourceId()); - LwM2mResource resource = null; - if (resource.isMultiInstances()) { + ResourceModel resource = context.getCtxServer().getResourceModel(registration, new LwM2mPath(path)); + if (resource.multiple) { this.onObservationSetResourcesValue(registration, null, ((LwM2mSingleResource) request.getNode()).getValues(), path); } else { this.onObservationSetResourcesValue(registration, ((LwM2mSingleResource) request.getNode()).getValue(), null, path); } - if (isDelayedUpdate) lwM2MClient.onSuccessOrErrorDelayedRequests(request.getPath().toString()); + if (isDelayedUpdate) lwM2mInMemorySecurityStore.getLwM2MClientWithReg(registration, null) + .onSuccessOrErrorDelayedRequests(request.getPath().toString()); } /** @@ -863,7 +833,7 @@ public class LwM2MTransportService { Set registrationIds = lwM2mInMemorySecurityStore.getSessions().entrySet() .stream() .filter(e -> e.getValue().getProfileUuid().equals(deviceProfile.getUuidId())) - .map(Map.Entry::getKey).sorted().collect(Collectors.toSet()); + .map(Map.Entry::getKey).sorted().collect(Collectors.toCollection(LinkedHashSet::new)); if (registrationIds.size() > 0) { this.onDeviceUpdateChangeProfile(registrationIds, deviceProfile); } @@ -968,11 +938,11 @@ public class LwM2MTransportService { if (sentAttrToThingsboard.getPathPostParametersAdd().size() > 0) { // update value in Resources registrationIds.forEach(registrationId -> { - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(registrationId); + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClientWithReg(null, registrationId); LeshanServer lwServer = lwM2MClient.getLwServer(); Registration registration = lwM2mInMemorySecurityStore.getByRegistration(registrationId); log.warn("[{}] # 4.1", registration.getEndpoint()); - this.updateResourceValueObserve(lwServer, registration, lwM2MClient, sentAttrToThingsboard.getPathPostParametersAdd(), GET_TYPE_OPER_READ); + this.updateResourceValueObserve(lwServer, registration, sentAttrToThingsboard.getPathPostParametersAdd(), GET_TYPE_OPER_READ); // sent attr/telemetry to tingsboard for new path this.updateAttrTelemetry(registration, false, sentAttrToThingsboard.getPathPostParametersAdd()); }); @@ -997,11 +967,11 @@ public class LwM2MTransportService { ResultsAnalyzerParameters postObserveAnalyzer = this.getAnalyzerParameters(sentObserveToClientOld.getPathPostParametersAdd(), sentObserveToClientNew.getPathPostParametersAdd()); // sent Request observe to Client registrationIds.forEach(registrationId -> { - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(registrationId); + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(null, registrationId); LeshanServer lwServer = lwM2MClient.getLwServer(); Registration registration = lwM2mInMemorySecurityStore.getByRegistration(registrationId); log.warn("[{}] # 5.1", registration.getEndpoint()); - this.updateResourceValueObserve(lwServer, registration, lwM2MClient, postObserveAnalyzer.getPathPostParametersAdd(), GET_TYPE_OPER_OBSERVE); + this.updateResourceValueObserve(lwServer, registration, postObserveAnalyzer.getPathPostParametersAdd(), GET_TYPE_OPER_OBSERVE); // 5.3 del // sent Request cancel observe to Client this.cancelObserveIsValue(lwServer, registration, postObserveAnalyzer.getPathPostParametersDel()); @@ -1052,10 +1022,9 @@ public class LwM2MTransportService { * * @param lwServer - LeshanServer * @param registration - Registration LwM2M Client - * @param lwM2MClient - object with All parameters off client * @param targets - path Resources == [ "/2/0/0", "/2/0/1"] */ - private void updateResourceValueObserve(LeshanServer lwServer, Registration registration, LwM2MClient lwM2MClient, Set targets, String typeOper) { + private void updateResourceValueObserve(LeshanServer lwServer, Registration registration, Set targets, String typeOper) { targets.forEach(target -> { LwM2mPath pathIds = new LwM2mPath(target); if (pathIds.isResource()) { @@ -1073,7 +1042,7 @@ public class LwM2MTransportService { } private void cancelObserveIsValue(LeshanServer lwServer, Registration registration, Set paramAnallyzer) { - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(registration.getId()); + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClientWithReg(registration, null); paramAnallyzer.forEach(p -> { if (this.getResourceValue(lwM2MClient, new LwM2mPath(p)) != null) { this.setCancelObservationRecourse(lwServer, registration, p); @@ -1130,7 +1099,7 @@ public class LwM2MTransportService { /** * if sessionInfo removed from sessions, then new registerAsyncSession - * @param sessionInfo + * @param sessionInfo - */ private void checkInactivity(SessionInfoProto sessionInfo) { if (transportService.reportActivity(sessionInfo) == null) { @@ -1138,20 +1107,14 @@ public class LwM2MTransportService { } } - public void sentLogsToThingsboard(String msg, String registrationId) { + public void sentLogsToThingsboard(String msg, Registration registration) { if (msg != null) { JsonObject telemetries = new JsonObject(); telemetries.addProperty(LOG_LW2M_TELEMETRY, msg); - this.updateParametersOnThingsboard(telemetries, LwM2MTransportHandler.DEVICE_TELEMETRY_TOPIC, registrationId); + this.updateParametersOnThingsboard(telemetries, LwM2MTransportHandler.DEVICE_TELEMETRY_TOPIC, registration); } } - private String getResourceName(String path) { - LwM2mPath resultIds = new LwM2mPath(path); - return (context.getCtxServer().getObjectModels().get(resultIds.getObjectId()) != null) ? - context.getCtxServer().getObjectModels().get(resultIds.getObjectId()).resources.get(resultIds.getResourceId()).name : ""; - } - /** * @param path - path resource * @return - value of Resource or null @@ -1160,6 +1123,6 @@ public class LwM2MTransportService { LwM2mPath pathIds = new LwM2mPath(path); ResourceValue resourceValue = this.getResourceValue(lwM2MClient, pathIds); return (resourceValue == null) ? null : - (String) this.converter.convertValue(resourceValue.getResourceValue(), this.context.getCtxServer().getResourceModelType(pathIds), ResourceModel.Type.STRING, pathIds); + (String) this.converter.convertValue(resourceValue.getResourceValue(), this.context.getCtxServer().getResourceModelType(lwM2MClient.getRegistration(), pathIds), ResourceModel.Type.STRING, pathIds); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java index 216136be8b..ad8dd4b0f8 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java @@ -129,8 +129,12 @@ public class LwM2mInMemorySecurityStore extends InMemorySecurityStore { return (modelClients != null) ? modelClients.getValue() : null; } - public LwM2MClient getLwM2MClient(String registrationId) { - return this.sessions.get(registrationId); + public LwM2MClient getLwM2MClientWithReg(Registration registration, String registrationId) { + return registrationId != null ? + this.sessions.get(registrationId) : + this.sessions.containsKey(registration.getId()) ? + this.sessions.get(registration.getId()) : + this.sessions.get(registration.getEndpoint()); } public LwM2MClient getLwM2MClient(TransportProtos.SessionInfoProto sessionInfo) { diff --git a/common/transport/transport-api/pom.xml b/common/transport/transport-api/pom.xml index 87a4562f81..77709c3ddc 100644 --- a/common/transport/transport-api/pom.xml +++ b/common/transport/transport-api/pom.xml @@ -114,9 +114,12 @@ org.eclipse.leshan leshan-core - 1.0.1 compile + + org.eclipse.leshan + leshan-server-cf + diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigServer.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigServer.java index 89c1600bf5..f2e398f063 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigServer.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigServer.java @@ -22,21 +22,25 @@ import org.eclipse.leshan.core.model.ObjectLoader; import org.eclipse.leshan.core.model.ObjectModel; import org.eclipse.leshan.core.model.ResourceModel; import org.eclipse.leshan.core.node.LwM2mPath; +import org.eclipse.leshan.server.registration.Registration; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; -import java.io.*; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; import java.nio.file.Path; import java.nio.file.Paths; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; +import java.util.Arrays; import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; @Slf4j @Component @@ -177,10 +181,6 @@ public class LwM2MTransportConfigServer { @Value("${transport.lwm2m.secure.redis_url:}") private String redisUrl; - @Getter - @Setter - private Map objectModels; - @PostConstruct public void init() { modelsValue = ObjectLoader.loadDefault(); @@ -196,7 +196,6 @@ public class LwM2MTransportConfigServer { log.error(" [{}] Read Models", path.getAbsoluteFile()); } getInKeyStore(); - this.objectModels = new ConcurrentHashMap(); } private File getPathModels() { @@ -248,21 +247,25 @@ public class LwM2MTransportConfigServer { return FULL_FILE_PATH.toUri().getPath(); } - public ResourceModel getResourceModel(LwM2mPath pathIds) { - return (this.objectModels.size()>0 && - this.objectModels.containsKey(pathIds.getObjectId()) && - this.objectModels.get(pathIds.getObjectId()).resources.containsKey(pathIds.getResourceId())) ? - this.objectModels.get(pathIds.getObjectId()).resources.get(pathIds.getResourceId()) : null; + public ResourceModel getResourceModel(Registration registration, LwM2mPath pathIds) { + String pathLink = "/" + pathIds.getObjectId() + "/" + pathIds.getObjectInstanceId(); + return (Arrays.stream(registration.getObjectLinks()).filter(p-> p.getUrl().equals(pathLink)).findFirst().isPresent() && + this.modelsValue.stream().filter(v -> v.id == pathIds.getObjectId()).collect(Collectors.toList()).size() > 0) && + this.modelsValue.stream().filter(v -> v.id == pathIds.getObjectId()).collect(Collectors.toList()).get(0).resources.containsKey(pathIds.getResourceId()) ? + this.modelsValue.stream().filter(v -> v.id == pathIds.getObjectId()).collect(Collectors.toList()).get(0).resources.get(pathIds.getResourceId()) : + null; } - public ResourceModel.Type getResourceModelType(LwM2mPath pathIds) { - ResourceModel resource = this.getResourceModel(pathIds); + public ResourceModel.Type getResourceModelType(Registration registration, LwM2mPath pathIds) { + ResourceModel resource = this.getResourceModel(registration, pathIds); return (resource == null) ? null : resource.type; } - public ResourceModel.Operations getOperation(LwM2mPath pathIds) { - ResourceModel resource = this.getResourceModel(pathIds); + public ResourceModel.Operations getOperation(Registration registration, LwM2mPath pathIds) { + ResourceModel resource = this.getResourceModel(registration, pathIds); return (resource == null) ? ResourceModel.Operations.NONE : resource.operations; } + + } diff --git a/pom.xml b/pom.xml index d87cc038d5..4522ea51bf 100755 --- a/pom.xml +++ b/pom.xml @@ -64,6 +64,7 @@ 2.2.6 2.2.3 1.0.1 + 1.0.1 1.0.0 2.6.2 2.3.30 @@ -1160,11 +1161,35 @@ leshan-server-redis ${leshan-server.version} + + org.eclipse.leshan + leshan-core + ${leshan-core.version} + org.eclipse.californium californium-core ${californium.version} + + org.eclipse.californium + californium-core + ${californium.version} + test-jar + test + + + org.eclipse.californium + californium-core + ${californium.version} + + + org.eclipse.californium + element-connector + ${californium.version} + test-jar + test + com.google.code.gson gson diff --git a/transport/lwm2m/pom.xml b/transport/lwm2m/pom.xml index 60a2d29d58..1d7619a2ad 100644 --- a/transport/lwm2m/pom.xml +++ b/transport/lwm2m/pom.xml @@ -78,14 +78,10 @@ org.eclipse.californium californium-core - ${californium.version} - test-jar - test org.eclipse.californium element-connector - ${californium.version} test-jar test From 429b3535cd6c019146f4aace70f4479a41fffacf Mon Sep 17 00:00:00 2001 From: Viacheslav Kukhtyn Date: Mon, 4 Jan 2021 11:15:24 +0200 Subject: [PATCH 018/249] Refactoring: use default method for MQTT client credentials --- .../rule/engine/mqtt/azure/AzureIotHubSasCredentials.java | 5 ----- .../rule/engine/mqtt/credentials/AnonymousCredentials.java | 6 ------ .../engine/mqtt/credentials/CertPemClientCredentials.java | 6 ------ .../rule/engine/mqtt/credentials/MqttClientCredentials.java | 3 ++- 4 files changed, 2 insertions(+), 18 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/AzureIotHubSasCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/AzureIotHubSasCredentials.java index f04e0fec96..5d7f475bec 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/AzureIotHubSasCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/AzureIotHubSasCredentials.java @@ -24,7 +24,6 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.binary.Base64; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.thingsboard.common.util.AzureIotHubUtil; -import org.thingsboard.mqtt.MqttClientConfig; import org.thingsboard.rule.engine.mqtt.credentials.MqttClientCredentials; import javax.net.ssl.TrustManagerFactory; @@ -59,10 +58,6 @@ public class AzureIotHubSasCredentials implements MqttClientCredentials { } } - @Override - public void configure(MqttClientConfig config) { - } - private TrustManagerFactory createAndInitTrustManagerFactory() throws Exception { X509Certificate caCertHolder; caCertHolder = readCertFile(caCert); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/AnonymousCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/AnonymousCredentials.java index 6a2302aff5..856682ba8c 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/AnonymousCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/AnonymousCredentials.java @@ -16,7 +16,6 @@ package org.thingsboard.rule.engine.mqtt.credentials; import io.netty.handler.ssl.SslContext; -import org.thingsboard.mqtt.MqttClientConfig; import java.util.Optional; @@ -26,10 +25,5 @@ public class AnonymousCredentials implements MqttClientCredentials { public Optional initSslContext() { return Optional.empty(); } - - @Override - public void configure(MqttClientConfig config) { - - } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/CertPemClientCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/CertPemClientCredentials.java index 3dcfc2dff8..df9f9f8275 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/CertPemClientCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/CertPemClientCredentials.java @@ -29,7 +29,6 @@ import org.bouncycastle.openssl.PEMKeyPair; import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder; import org.springframework.util.StringUtils; -import org.thingsboard.mqtt.MqttClientConfig; import javax.crypto.Cipher; import javax.crypto.EncryptedPrivateKeyInfo; @@ -80,11 +79,6 @@ public class CertPemClientCredentials implements MqttClientCredentials { } } - @Override - public void configure(MqttClientConfig config) { - - } - private KeyManagerFactory createAndInitKeyManagerFactory() throws Exception { X509Certificate certHolder = readCertFile(cert); Object keyObject = readPrivateKeyFile(privateKey); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttClientCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttClientCredentials.java index 1c397614ea..4814fb3afb 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttClientCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttClientCredentials.java @@ -36,6 +36,7 @@ public interface MqttClientCredentials { Optional initSslContext(); - void configure(MqttClientConfig config); + default void configure(MqttClientConfig config) { + } } From 58e544c32e6f2274a3084a1ba1509a020fa2d59d Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Tue, 5 Jan 2021 10:50:17 +0200 Subject: [PATCH 019/249] Make LwM2mValueConverterImpl singleton --- .../transport/lwm2m/server/LwM2MTransportRequest.java | 2 +- .../lwm2m/server/LwM2MTransportServerConfiguration.java | 4 ++-- .../transport/lwm2m/server/LwM2MTransportService.java | 2 +- .../server/transport/lwm2m/server/client/LwM2MClient.java | 2 +- .../transport/lwm2m/utils/LwM2mValueConverterImpl.java | 6 ++++++ 5 files changed, 11 insertions(+), 5 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java index e919835a1a..5ee37ac380 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java @@ -91,7 +91,7 @@ public class LwM2MTransportRequest { @PostConstruct public void init() { - this.converter = new LwM2mValueConverterImpl(); + this.converter = LwM2mValueConverterImpl.getInstance(); executorResponse = Executors.newCachedThreadPool( new NamedThreadFactory(String.format("LwM2M %s channel response", RESPONSE_CHANNEL))); executorResponseError = Executors.newCachedThreadPool( diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerConfiguration.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerConfiguration.java index 2725e80e2b..c17400ede8 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerConfiguration.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerConfiguration.java @@ -73,7 +73,7 @@ public class LwM2MTransportServerConfiguration { builder.setEncoder(new DefaultLwM2mNodeEncoder()); LwM2mNodeDecoder decoder = new DefaultLwM2mNodeDecoder(); builder.setDecoder(decoder); - builder.setEncoder(new DefaultLwM2mNodeEncoder(new LwM2mValueConverterImpl())); + builder.setEncoder(new DefaultLwM2mNodeEncoder(LwM2mValueConverterImpl.getInstance())); /** Create CoAP Config */ builder.setCoapConfig(getCoapConfig()); @@ -89,7 +89,7 @@ public class LwM2MTransportServerConfiguration { builder.setDtlsConfig(dtlsConfig); /** Use a magic converter to support bad type send by the UI. */ - builder.setEncoder(new DefaultLwM2mNodeEncoder(new LwM2mValueConverterImpl())); + builder.setEncoder(new DefaultLwM2mNodeEncoder(LwM2mValueConverterImpl.getInstance())); /** Create DTLS security mode * There can be only one DTLS security mode diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java index d031e63c89..9b082ce09f 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java @@ -123,7 +123,7 @@ public class LwM2MTransportService { new NamedThreadFactory(String.format("LwM2M %s channel update registered", SERVICE_CHANNEL))); this.executorUnRegistered = Executors.newCachedThreadPool( new NamedThreadFactory(String.format("LwM2M %s channel un registered", SERVICE_CHANNEL))); - this.converter = new LwM2mValueConverterImpl(); + this.converter = LwM2mValueConverterImpl.getInstance(); } /** diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java index e91f8479e2..6519b5cd33 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java @@ -78,7 +78,7 @@ public class LwM2MClient implements Cloneable { * Key , response instance -> resources: value...> */ this.responses = new ConcurrentHashMap<>(); - this.converter = new LwM2mValueConverterImpl(); + this.converter = LwM2mValueConverterImpl.getInstance(); } /** diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java index 44fcfad9b6..cca1effae4 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java @@ -33,6 +33,12 @@ import java.util.Date; @Slf4j public class LwM2mValueConverterImpl implements LwM2mValueConverter { + private static final LwM2mValueConverterImpl INSTANCE = new LwM2mValueConverterImpl(); + + public static LwM2mValueConverterImpl getInstance() { + return INSTANCE; + } + @Override public Object convertValue(Object value, Type currentType, Type expectedType, LwM2mPath resourcePath) throws CodecException { From bc4684c907ecebf581e8c6b4dd9763c6fa0af1fa Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 5 Jan 2021 15:50:41 +0200 Subject: [PATCH 020/249] Lwm2m: backEnd: refactoring security --- ...TransportBootstrapServerConfiguration.java | 176 ++- .../secure/LwM2MBootstrapSecurityStore.java | 74 +- .../LwM2MSetSecurityStoreBootstrap.java | 205 --- .../secure/LWM2MGenerationPSkRPkECC.java | 6 +- ...LwM2mValidateCredentialsSecurityInfo.java} | 45 +- .../lwm2m/server/LwM2MSessionMsgListener.java | 4 +- .../lwm2m/server/LwM2MTransportHandler.java | 66 +- .../lwm2m/server/LwM2MTransportRequest.java | 2 +- .../LwM2MTransportServerConfiguration.java | 221 +++- .../LwM2MTransportServerInitializer.java | 47 +- .../lwm2m/server/LwM2MTransportService.java | 1098 +--------------- .../server/LwM2MTransportServiceImpl.java | 1132 +++++++++++++++++ .../lwm2m/server/LwM2mServerListener.java | 17 +- .../lwm2m/server/client/LwM2MClient.java | 8 +- .../secure/LwM2MSetSecurityStoreServer.java | 241 ---- .../secure/LwM2mInMemorySecurityStore.java | 100 +- .../lwm2m/utils/LwM2mValueConverterImpl.java | 1 - netty-mqtt/pom.xml | 7 +- pom.xml | 2 +- 19 files changed, 1750 insertions(+), 1702 deletions(-) delete mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MSetSecurityStoreBootstrap.java rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/{LwM2MGetSecurityInfo.java => LwM2mValidateCredentialsSecurityInfo.java} (80%) create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServiceImpl.java delete mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2MSetSecurityStoreServer.java diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerConfiguration.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerConfiguration.java index a1f056ff30..588de9bba2 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerConfiguration.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerConfiguration.java @@ -18,6 +18,7 @@ package org.thingsboard.server.transport.lwm2m.bootstrap; import lombok.extern.slf4j.Slf4j; import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.eclipse.leshan.core.model.StaticModel; +import org.eclipse.leshan.core.util.Hex; import org.eclipse.leshan.server.bootstrap.BootstrapSessionManager; import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServer; import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServerBuilder; @@ -28,18 +29,40 @@ import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Component; import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapSecurityStore; import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MInMemoryBootstrapConfigStore; -import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MSetSecurityStoreBootstrap; import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2mDefaultBootstrapSessionManager; import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode; import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportContextServer; -import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.X509; + +import java.math.BigInteger; +import java.security.AlgorithmParameters; +import java.security.GeneralSecurityException; +import java.security.KeyFactory; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; +import java.security.interfaces.ECPublicKey; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPoint; +import java.security.spec.ECPrivateKeySpec; +import java.security.spec.ECPublicKeySpec; +import java.security.spec.KeySpec; +import java.util.Arrays; + +import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.NO_SEC; import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.RPK; +import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.X509; import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.getCoapConfig; @Slf4j @Component @ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true'&& '${transport.lwm2m.bootstrap.enable:false}'=='true') || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true'&& '${transport.lwm2m.bootstrap.enable}'=='true')") public class LwM2MTransportBootstrapServerConfiguration { + private PublicKey publicKey; + private PrivateKey privateKey; @Autowired private LwM2MTransportContextBootstrap contextBs; @@ -90,7 +113,7 @@ public class LwM2MTransportBootstrapServerConfiguration { builder.setDtlsConfig(dtlsConfig); /** Create credentials */ - new LwM2MSetSecurityStoreBootstrap(builder, contextBs, contextS, dtlsMode); + LwM2MSetSecurityStoreBootstrap(builder, dtlsMode); BootstrapSessionManager sessionManager = new LwM2mDefaultBootstrapSessionManager(lwM2MBootstrapSecurityStore); builder.setSessionManager(sessionManager); @@ -98,4 +121,151 @@ public class LwM2MTransportBootstrapServerConfiguration { /** Create BootstrapServer */ return builder.build(); } + + public void LwM2MSetSecurityStoreBootstrap(LeshanBootstrapServerBuilder builder, LwM2MSecurityMode dtlsMode) { + + /** Set securityStore with new registrationStore */ + + switch (dtlsMode) { + /** Use No_Sec only */ + case NO_SEC: + setServerWithX509Cert(builder, NO_SEC.code); + break; + /** Use PSK/RPK */ + case PSK: + case RPK: + setRPK(builder); + break; + case X509: + setServerWithX509Cert(builder, X509.code); + break; + /** Use X509_EST only */ + case X509_EST: + // TODO support sentinel pool and make pool configurable + break; + /** Use ather X509, PSK, No_Sec ?? */ + default: + break; + } + } + + private void setRPK(LeshanBootstrapServerBuilder builder) { + try { + /** Get Elliptic Curve Parameter spec for secp256r1 */ + AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC"); + algoParameters.init(new ECGenParameterSpec("secp256r1")); + ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class); + if (this.contextBs.getCtxBootStrap().getBootstrapPublicX() != null && !this.contextBs.getCtxBootStrap().getBootstrapPublicX().isEmpty() && this.contextBs.getCtxBootStrap().getBootstrapPublicY() != null && !this.contextBs.getCtxBootStrap().getBootstrapPublicY().isEmpty()) { + /** Get point values */ + byte[] publicX = Hex.decodeHex(this.contextBs.getCtxBootStrap().getBootstrapPublicX().toCharArray()); + byte[] publicY = Hex.decodeHex(this.contextBs.getCtxBootStrap().getBootstrapPublicY().toCharArray()); + /** Create key specs */ + KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)), + parameterSpec); + /** Get keys */ + this.publicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec); + } + if (this.contextBs.getCtxBootStrap().getBootstrapPrivateS() != null && !this.contextBs.getCtxBootStrap().getBootstrapPrivateS().isEmpty()) { + /** Get point values */ + byte[] privateS = Hex.decodeHex(this.contextBs.getCtxBootStrap().getBootstrapPrivateS().toCharArray()); + /** Create key specs */ + KeySpec privateKeySpec = new ECPrivateKeySpec(new BigInteger(privateS), parameterSpec); + /** Get keys */ + this.privateKey = KeyFactory.getInstance("EC").generatePrivate(privateKeySpec); + } + if (this.publicKey != null && this.publicKey.getEncoded().length > 0 && + this.privateKey != null && this.privateKey.getEncoded().length > 0) { + builder.setPublicKey(this.publicKey); + builder.setPrivateKey(this.privateKey); + this.contextBs.getCtxBootStrap().setBootstrapPublicKey(this.publicKey); + getParamsRPK(); + } + } catch (GeneralSecurityException | IllegalArgumentException e) { + log.error("[{}] Failed generate Server PSK/RPK", e.getMessage()); + throw new RuntimeException(e); + } + } + + private void setServerWithX509Cert(LeshanBootstrapServerBuilder builder, int securityModeCode) { + try { + if (this.contextS.getCtxServer().getKeyStoreValue() != null) { + KeyStore keyStoreServer = this.contextS.getCtxServer().getKeyStoreValue(); + setBuilderX509(builder); + X509Certificate rootCAX509Cert = (X509Certificate) keyStoreServer.getCertificate(this.contextS.getCtxServer().getRootAlias()); + if (rootCAX509Cert != null && securityModeCode == X509.code) { + X509Certificate[] trustedCertificates = new X509Certificate[1]; + trustedCertificates[0] = rootCAX509Cert; + builder.setTrustedCertificates(trustedCertificates); + } else { + /** by default trust all */ + builder.setTrustedCertificates(new X509Certificate[0]); + } + } + else { + /** by default trust all */ + builder.setTrustedCertificates(new X509Certificate[0]); + log.error("Unable to load X509 files for BootStrapServer"); + } + } catch (KeyStoreException ex) { + log.error("[{}] Unable to load X509 files server", ex.getMessage()); + } + + } + + private void setBuilderX509(LeshanBootstrapServerBuilder builder) { + /** + * For deb => KeyStorePathFile == yml or commandline: KEY_STORE_PATH_FILE + * For idea => KeyStorePathResource == common/transport/lwm2m/src/main/resources/credentials: in LwM2MTransportContextServer: credentials/serverKeyStore.jks + */ + try { + X509Certificate serverCertificate = (X509Certificate) this.contextS.getCtxServer().getKeyStoreValue().getCertificate(this.contextBs.getCtxBootStrap().getBootstrapAlias()); + this.privateKey = (PrivateKey) this.contextS.getCtxServer().getKeyStoreValue().getKey(this.contextBs.getCtxBootStrap().getBootstrapAlias(), this.contextS.getCtxServer().getKeyStorePasswordServer() == null ? null : this.contextS.getCtxServer().getKeyStorePasswordServer().toCharArray()); + if (this.privateKey != null && this.privateKey.getEncoded().length > 0) { + builder.setPrivateKey(this.privateKey); + } + if (serverCertificate != null) { + builder.setCertificateChain(new X509Certificate[]{serverCertificate}); + this.contextBs.getCtxBootStrap().setBootstrapCertificate(serverCertificate); + infoParamsX509(serverCertificate); + } + } catch (Exception ex) { + log.error("[{}] Unable to load KeyStore files server", ex.getMessage()); + } + } + + private void getParamsRPK() { + if (this.publicKey instanceof ECPublicKey) { + /** Get x coordinate */ + byte[] x = ((ECPublicKey) this.publicKey).getW().getAffineX().toByteArray(); + if (x[0] == 0) + x = Arrays.copyOfRange(x, 1, x.length); + + /** Get Y coordinate */ + byte[] y = ((ECPublicKey) this.publicKey).getW().getAffineY().toByteArray(); + if (y[0] == 0) + y = Arrays.copyOfRange(y, 1, y.length); + + /** Get Curves params */ + String params = ((ECPublicKey) this.publicKey).getParams().toString(); + log.info( + " \nBootstrap uses RPK : \n Elliptic Curve parameters : [{}] \n Public x coord : [{}] \n Public y coord : [{}] \n Public Key (Hex): [{}] \n Private Key (Hex): [{}]", + params, Hex.encodeHexString(x), Hex.encodeHexString(y), + Hex.encodeHexString(this.publicKey.getEncoded()), + Hex.encodeHexString(this.privateKey.getEncoded())); + } else { + throw new IllegalStateException("Unsupported Public Key Format (only ECPublicKey supported)."); + } + } + + private void infoParamsX509(X509Certificate certificate) { + try { + log.info("BootStrap uses X509 : \n X509 Certificate (Hex): [{}] \n Private Key (Hex): [{}]", + Hex.encodeHexString(certificate.getEncoded()), + Hex.encodeHexString(this.privateKey.getEncoded())); + } catch (CertificateEncodingException e) { + log.error("", e); + } + } + + } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java index a4e49fc546..6d21d48c65 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java @@ -29,10 +29,10 @@ import org.eclipse.leshan.server.security.BootstrapSecurityStore; import org.eclipse.leshan.server.security.SecurityInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; -import org.springframework.stereotype.Component; +import org.springframework.stereotype.Service; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.transport.lwm2m.secure.LwM2MGetSecurityInfo; import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode; +import org.thingsboard.server.transport.lwm2m.secure.LwM2mValidateCredentialsSecurityInfo; import org.thingsboard.server.transport.lwm2m.secure.ReadResultSecurityStore; import org.thingsboard.server.transport.lwm2m.server.LwM2MSessionMsgListener; import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportContextServer; @@ -53,14 +53,14 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandle import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.getBootstrapParametersFromThingsboard; @Slf4j -@Component("LwM2MBootstrapSecurityStore") +@Service("LwM2MBootstrapSecurityStore") @ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' && '${transport.lwm2m.bootstrap.enable:false}'=='true') || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true' && '${transport.lwm2m.bootstrap.enable}'=='true')") public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { private final EditableBootstrapConfigStore bootstrapConfigStore; @Autowired - LwM2MGetSecurityInfo lwM2MGetSecurityInfo; + LwM2mValidateCredentialsSecurityInfo lwM2MValidateCredentialsSecurityInfo; @Autowired public LwM2MTransportContextServer context; @@ -72,8 +72,8 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { @Override public List getAllByEndpoint(String endPoint) { String endPointKey = endPoint; - ReadResultSecurityStore store = lwM2MGetSecurityInfo.getSecurityInfo(endPointKey, TypeServer.BOOTSTRAP); - if (store.getBootstrapJsonCredential() != null) { + ReadResultSecurityStore store = lwM2MValidateCredentialsSecurityInfo.validateCredentialsSecurityInfo(endPointKey, TypeServer.BOOTSTRAP); + if (store.getBootstrapJsonCredential() != null && store.getSecurityMode() < LwM2MSecurityMode.DEFAULT_MODE.code) { /** add value to store from BootstrapJson */ this.setBootstrapConfigScurityInfo(store); BootstrapConfig bsConfigNew = store.getBootstrapConfig(); @@ -86,7 +86,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { } bootstrapConfigStore.add(endPoint, bsConfigNew); } catch (InvalidConfigurationException e) { - e.printStackTrace(); + log.error("", e); } return store.getSecurityInfo() == null ? null : Arrays.asList(store.getSecurityInfo()); } @@ -96,17 +96,16 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { @Override public SecurityInfo getByIdentity(String identity) { - ReadResultSecurityStore store = lwM2MGetSecurityInfo.getSecurityInfo(identity, TypeServer.BOOTSTRAP); - /** add value to store from BootstrapJson */ - this.setBootstrapConfigScurityInfo(store); - - if (store.getSecurityMode() < LwM2MSecurityMode.DEFAULT_MODE.code) { + ReadResultSecurityStore store = lwM2MValidateCredentialsSecurityInfo.validateCredentialsSecurityInfo(identity, TypeServer.BOOTSTRAP); + if (store.getBootstrapJsonCredential() != null && store.getSecurityMode() < LwM2MSecurityMode.DEFAULT_MODE.code) { + /** add value to store from BootstrapJson */ + this.setBootstrapConfigScurityInfo(store); BootstrapConfig bsConfig = store.getBootstrapConfig(); if (bsConfig.security != null) { try { bootstrapConfigStore.add(store.getEndPoint(), bsConfig); } catch (InvalidConfigurationException e) { - e.printStackTrace(); + log.error("", e); } return store.getSecurityInfo(); } @@ -154,33 +153,36 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { private LwM2MBootstrapConfig getParametersBootstrap(ReadResultSecurityStore store) { try { JsonObject bootstrapJsonCredential = store.getBootstrapJsonCredential(); - ObjectMapper mapper = new ObjectMapper(); - LwM2MBootstrapConfig lwM2MBootstrapConfig = mapper.readValue(bootstrapJsonCredential.toString(), LwM2MBootstrapConfig.class); - JsonObject bootstrapObject = getBootstrapParametersFromThingsboard(store.getDeviceProfile()); - lwM2MBootstrapConfig.servers = mapper.readValue(bootstrapObject.get(SERVERS).toString(), LwM2MBootstrapServers.class); - LwM2MServerBootstrap profileServerBootstrap = mapper.readValue(bootstrapObject.get(BOOTSTRAP_SERVER).toString(), LwM2MServerBootstrap.class); - LwM2MServerBootstrap profileLwm2mServer = mapper.readValue(bootstrapObject.get(LWM2M_SERVER).toString(), LwM2MServerBootstrap.class); - UUID sessionUUiD = UUID.randomUUID(); - TransportProtos.SessionInfoProto sessionInfo = context.getValidateSessionInfo(store.getMsg(), sessionUUiD.getMostSignificantBits(), sessionUUiD.getLeastSignificantBits()); - context.getTransportService().registerAsyncSession(sessionInfo, new LwM2MSessionMsgListener(null, sessionInfo)); - if (this.getValidatedSecurityMode(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap, lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer)) { - lwM2MBootstrapConfig.bootstrapServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap); - lwM2MBootstrapConfig.lwm2mServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer); - String logMsg = String.format(LOG_LW2M_INFO + ": getParametersBootstrap: %s Access connect client with bootstrap server.", store.getEndPoint()); - context.sentParametersOnThingsboard(context.getTelemetryMsgObject(logMsg), LwM2MTransportHandler.DEVICE_TELEMETRY_TOPIC, sessionInfo); - return lwM2MBootstrapConfig; - } - else { - log.error(" [{}] Different values SecurityMode between of client and profile.", store.getEndPoint()); - log.error(LOG_LW2M_ERROR + " getParametersBootstrap: [{}] Different values SecurityMode between of client and profile.", store.getEndPoint()); - String logMsg = String.format(LOG_LW2M_ERROR + ": getParametersBootstrap: %s Different values SecurityMode between of client and profile.", store.getEndPoint()); - context.sentParametersOnThingsboard(context.getTelemetryMsgObject(logMsg), LwM2MTransportHandler.DEVICE_TELEMETRY_TOPIC, sessionInfo); - return null; + if (bootstrapJsonCredential != null) { + ObjectMapper mapper = new ObjectMapper(); + LwM2MBootstrapConfig lwM2MBootstrapConfig = mapper.readValue(bootstrapJsonCredential.toString(), LwM2MBootstrapConfig.class); + JsonObject bootstrapObject = getBootstrapParametersFromThingsboard(store.getDeviceProfile()); + lwM2MBootstrapConfig.servers = mapper.readValue(bootstrapObject.get(SERVERS).toString(), LwM2MBootstrapServers.class); + LwM2MServerBootstrap profileServerBootstrap = mapper.readValue(bootstrapObject.get(BOOTSTRAP_SERVER).toString(), LwM2MServerBootstrap.class); + LwM2MServerBootstrap profileLwm2mServer = mapper.readValue(bootstrapObject.get(LWM2M_SERVER).toString(), LwM2MServerBootstrap.class); + UUID sessionUUiD = UUID.randomUUID(); + TransportProtos.SessionInfoProto sessionInfo = context.getValidateSessionInfo(store.getMsg(), sessionUUiD.getMostSignificantBits(), sessionUUiD.getLeastSignificantBits()); + context.getTransportService().registerAsyncSession(sessionInfo, new LwM2MSessionMsgListener(null, sessionInfo)); + if (this.getValidatedSecurityMode(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap, lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer)) { + lwM2MBootstrapConfig.bootstrapServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap); + lwM2MBootstrapConfig.lwm2mServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer); + String logMsg = String.format(LOG_LW2M_INFO + ": getParametersBootstrap: %s Access connect client with bootstrap server.", store.getEndPoint()); + context.sentParametersOnThingsboard(context.getTelemetryMsgObject(logMsg), LwM2MTransportHandler.DEVICE_TELEMETRY_TOPIC, sessionInfo); + return lwM2MBootstrapConfig; + } else { + log.error(" [{}] Different values SecurityMode between of client and profile.", store.getEndPoint()); + log.error(LOG_LW2M_ERROR + " getParametersBootstrap: [{}] Different values SecurityMode between of client and profile.", store.getEndPoint()); + String logMsg = String.format(LOG_LW2M_ERROR + ": getParametersBootstrap: %s Different values SecurityMode between of client and profile.", store.getEndPoint()); + context.sentParametersOnThingsboard(context.getTelemetryMsgObject(logMsg), LwM2MTransportHandler.DEVICE_TELEMETRY_TOPIC, sessionInfo); + return null; + } } } catch (JsonProcessingException e) { log.error("Unable to decode Json or Certificate for [{}] [{}]", store.getEndPoint(), e.getMessage()); return null; } + log.error("Unable to decode Json or Certificate for [{}]", store.getEndPoint()); + return null; } /** @@ -193,7 +195,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { * @return false if not sync between SecurityMode of Bootstrap credential and profile */ private boolean getValidatedSecurityMode(LwM2MServerBootstrap bootstrapFromCredential, LwM2MServerBootstrap profileServerBootstrap, LwM2MServerBootstrap lwm2mFromCredential, LwM2MServerBootstrap profileLwm2mServer) { - return (bootstrapFromCredential.getSecurityMode().equals(profileServerBootstrap.getSecurityMode()) && + return (bootstrapFromCredential.getSecurityMode().equals(profileServerBootstrap.getSecurityMode()) && lwm2mFromCredential.getSecurityMode().equals(profileLwm2mServer.getSecurityMode())); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MSetSecurityStoreBootstrap.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MSetSecurityStoreBootstrap.java deleted file mode 100644 index f648799204..0000000000 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MSetSecurityStoreBootstrap.java +++ /dev/null @@ -1,205 +0,0 @@ -/** - * Copyright © 2016-2020 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.thingsboard.server.transport.lwm2m.bootstrap.secure; - -import lombok.Data; -import lombok.extern.slf4j.Slf4j; -import org.eclipse.leshan.core.util.Hex; -import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServerBuilder; -import org.eclipse.leshan.server.security.EditableSecurityStore; -import org.thingsboard.server.transport.lwm2m.bootstrap.LwM2MTransportContextBootstrap; -import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode; -import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportContextServer; - -import java.math.BigInteger; -import java.security.AlgorithmParameters; -import java.security.KeyStore; -import java.security.PublicKey; -import java.security.PrivateKey; -import java.security.KeyFactory; -import java.security.GeneralSecurityException; -import java.security.KeyStoreException; -import java.security.cert.X509Certificate; -import java.security.interfaces.ECPublicKey; -import java.security.spec.ECGenParameterSpec; -import java.security.spec.ECParameterSpec; -import java.security.spec.ECPublicKeySpec; -import java.security.spec.ECPoint; -import java.security.spec.KeySpec; -import java.security.spec.ECPrivateKeySpec; -import java.util.Arrays; - -import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.NO_SEC; -import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.X509; - -@Slf4j -@Data -public class LwM2MSetSecurityStoreBootstrap { - - private KeyStore keyStore; - private PublicKey publicKey; - private PrivateKey privateKey; - private LwM2MTransportContextBootstrap contextBs; - private LwM2MTransportContextServer contextS; - private LeshanBootstrapServerBuilder builder; - EditableSecurityStore securityStore; - - public LwM2MSetSecurityStoreBootstrap(LeshanBootstrapServerBuilder builder, LwM2MTransportContextBootstrap contextBs, LwM2MTransportContextServer contextS, LwM2MSecurityMode dtlsMode) { - this.builder = builder; - this.contextBs = contextBs; - this.contextS = contextS; - /** Set securityStore with new registrationStore */ - - switch (dtlsMode) { - /** Use No_Sec only */ - case NO_SEC: - setServerWithX509Cert(NO_SEC.code); - break; - /** Use PSK/RPK */ - case PSK: - case RPK: - setRPK(); - break; - case X509: - setServerWithX509Cert(X509.code); - break; - /** Use X509_EST only */ - case X509_EST: - // TODO support sentinel pool and make pool configurable - break; - /** Use ather X509, PSK, No_Sec ?? */ - default: - break; - } - } - - private void setRPK() { - try { - /** Get Elliptic Curve Parameter spec for secp256r1 */ - AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC"); - algoParameters.init(new ECGenParameterSpec("secp256r1")); - ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class); - if (this.contextBs.getCtxBootStrap().getBootstrapPublicX() != null && !this.contextBs.getCtxBootStrap().getBootstrapPublicX().isEmpty() && this.contextBs.getCtxBootStrap().getBootstrapPublicY() != null && !this.contextBs.getCtxBootStrap().getBootstrapPublicY().isEmpty()) { - /** Get point values */ - byte[] publicX = Hex.decodeHex(this.contextBs.getCtxBootStrap().getBootstrapPublicX().toCharArray()); - byte[] publicY = Hex.decodeHex(this.contextBs.getCtxBootStrap().getBootstrapPublicY().toCharArray()); - /** Create key specs */ - KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)), - parameterSpec); - /** Get keys */ - this.publicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec); - } - if (this.contextBs.getCtxBootStrap().getBootstrapPrivateS() != null && !this.contextBs.getCtxBootStrap().getBootstrapPrivateS().isEmpty()) { - /** Get point values */ - byte[] privateS = Hex.decodeHex(this.contextBs.getCtxBootStrap().getBootstrapPrivateS().toCharArray()); - /** Create key specs */ - KeySpec privateKeySpec = new ECPrivateKeySpec(new BigInteger(privateS), parameterSpec); - /** Get keys */ - this.privateKey = KeyFactory.getInstance("EC").generatePrivate(privateKeySpec); - } - if (this.publicKey != null && this.publicKey.getEncoded().length > 0 && - this.privateKey != null && this.privateKey.getEncoded().length > 0) { - this.builder.setPublicKey(this.publicKey); - this.builder.setPrivateKey(this.privateKey); - this.contextBs.getCtxBootStrap().setBootstrapPublicKey(this.publicKey); - getParamsRPK(); - } - } catch (GeneralSecurityException | IllegalArgumentException e) { - log.error("[{}] Failed generate Server PSK/RPK", e.getMessage()); - throw new RuntimeException(e); - } - } - - private void setServerWithX509Cert(int securityModeCode) { - try { - if (this.contextS.getCtxServer().getKeyStoreValue() != null) { - KeyStore keyStoreServer = this.contextS.getCtxServer().getKeyStoreValue(); - setBuilderX509(); - X509Certificate rootCAX509Cert = (X509Certificate) keyStoreServer.getCertificate(this.contextS.getCtxServer().getRootAlias()); - if (rootCAX509Cert != null && securityModeCode == X509.code) { - X509Certificate[] trustedCertificates = new X509Certificate[1]; - trustedCertificates[0] = rootCAX509Cert; - this.builder.setTrustedCertificates(trustedCertificates); - } else { - /** by default trust all */ - this.builder.setTrustedCertificates(new X509Certificate[0]); - } - } - else { - /** by default trust all */ - this.builder.setTrustedCertificates(new X509Certificate[0]); - log.error("Unable to load X509 files for BootStrapServer"); - } - } catch (KeyStoreException ex) { - log.error("[{}] Unable to load X509 files server", ex.getMessage()); - } - - } - - private void setBuilderX509() { - /** - * For deb => KeyStorePathFile == yml or commandline: KEY_STORE_PATH_FILE - * For idea => KeyStorePathResource == common/transport/lwm2m/src/main/resources/credentials: in LwM2MTransportContextServer: credentials/serverKeyStore.jks - */ - try { - X509Certificate serverCertificate = (X509Certificate) this.contextS.getCtxServer().getKeyStoreValue().getCertificate(this.contextBs.getCtxBootStrap().getBootstrapAlias()); - this.privateKey = (PrivateKey) this.contextS.getCtxServer().getKeyStoreValue().getKey(this.contextBs.getCtxBootStrap().getBootstrapAlias(), this.contextS.getCtxServer().getKeyStorePasswordServer() == null ? null : this.contextS.getCtxServer().getKeyStorePasswordServer().toCharArray()); - if (this.privateKey != null && this.privateKey.getEncoded().length > 0) { - this.builder.setPrivateKey(this.privateKey); - } - if (serverCertificate != null) { - this.builder.setCertificateChain(new X509Certificate[]{serverCertificate}); - this.contextBs.getCtxBootStrap().setBootstrapCertificate(serverCertificate); - } - } catch (Exception ex) { - log.error("[{}] Unable to load KeyStore files server", ex.getMessage()); - } - } - - private void getParamsRPK() { - if (this.publicKey instanceof ECPublicKey) { - /** Get x coordinate */ - byte[] x = ((ECPublicKey) this.publicKey).getW().getAffineX().toByteArray(); - if (x[0] == 0) - x = Arrays.copyOfRange(x, 1, x.length); - - /** Get Y coordinate */ - byte[] y = ((ECPublicKey) this.publicKey).getW().getAffineY().toByteArray(); - if (y[0] == 0) - y = Arrays.copyOfRange(y, 1, y.length); - - /** Get Curves params */ - String params = ((ECPublicKey) this.publicKey).getParams().toString(); - log.info( - " \nBootstrap uses RPK : \n Elliptic Curve parameters : [{}] \n Public x coord : [{}] \n Public y coord : [{}] \n Public Key (Hex): [{}] \n Private Key (Hex): [{}]", - params, Hex.encodeHexString(x), Hex.encodeHexString(y), - Hex.encodeHexString(this.publicKey.getEncoded()), - Hex.encodeHexString(this.privateKey.getEncoded())); - } else { - throw new IllegalStateException("Unsupported Public Key Format (only ECPublicKey supported)."); - } - } - -// private void getParamsX509() { -// try { -// log.info("BootStrap uses X509 : \n X509 Certificate (Hex): [{}] \n Private Key (Hex): [{}]", -// Hex.encodeHexString(this.certificate.getEncoded()), -// Hex.encodeHexString(this.privateKey.getEncoded())); -// } catch (CertificateEncodingException e) { -// e.printStackTrace(); -// } -// } -} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LWM2MGenerationPSkRPkECC.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LWM2MGenerationPSkRPkECC.java index 1d70ae2d83..0921df1104 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LWM2MGenerationPSkRPkECC.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LWM2MGenerationPSkRPkECC.java @@ -73,15 +73,15 @@ public class LWM2MGenerationPSkRPkECC { try { kpg = KeyPairGenerator.getInstance(algorithm, provider); } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); + log.error("", e); } catch (NoSuchProviderException e) { - e.printStackTrace(); + log.error("", e); } ECGenParameterSpec ecsp = new ECGenParameterSpec(nameParameterSpec); try { kpg.initialize(ecsp); } catch (InvalidAlgorithmParameterException e) { - e.printStackTrace(); + log.error("", e); } KeyPair kp = kpg.genKeyPair(); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2MGetSecurityInfo.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mValidateCredentialsSecurityInfo.java similarity index 80% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2MGetSecurityInfo.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mValidateCredentialsSecurityInfo.java index a02107ca45..0983f9c87f 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2MGetSecurityInfo.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mValidateCredentialsSecurityInfo.java @@ -44,11 +44,10 @@ import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.PS import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.RPK; import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.X509; - @Slf4j @Component("LwM2MGetSecurityInfo") @ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' ) || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") -public class LwM2MGetSecurityInfo { +public class LwM2mValidateCredentialsSecurityInfo { @Autowired public LwM2MTransportContextServer contextS; @@ -57,7 +56,13 @@ public class LwM2MGetSecurityInfo { public LwM2MTransportContextBootstrap contextBS; - public ReadResultSecurityStore getSecurityInfo(String endPoint, TypeServer keyValue) { + /** + * Request to thingsboard Response from thingsboard ValidateDeviceLwM2MCredentials + * @param endPoint - + * @param keyValue - + * @return ValidateDeviceCredentialsResponseMsg and SecurityInfo + */ + public ReadResultSecurityStore validateCredentialsSecurityInfo(String endPoint, TypeServer keyValue) { CountDownLatch latch = new CountDownLatch(1); final ReadResultSecurityStore[] resultSecurityStore = new ReadResultSecurityStore[1]; contextS.getTransportService().process(ValidateDeviceLwM2MCredentialsRequestMsg.newBuilder().setCredentialsId(endPoint).build(), @@ -65,7 +70,7 @@ public class LwM2MGetSecurityInfo { @Override public void onSuccess(ValidateDeviceCredentialsResponseMsg msg) { String credentialsBody = msg.getCredentialsBody(); - resultSecurityStore[0] = putSecurityInfo(endPoint, msg.getDeviceInfo().getDeviceName(), credentialsBody, keyValue); + resultSecurityStore[0] = createSecurityInfo(endPoint, credentialsBody, keyValue); resultSecurityStore[0].setMsg(msg); Optional deviceProfileOpt = LwM2MTransportHandler.decode(msg.getProfileBody().toByteArray()); deviceProfileOpt.ifPresent(profile -> resultSecurityStore[0].setDeviceProfile(profile)); @@ -74,20 +79,27 @@ public class LwM2MGetSecurityInfo { @Override public void onError(Throwable e) { - log.trace("[{}] Failed to process credentials PSK: {}", endPoint, e); - resultSecurityStore[0] = putSecurityInfo(endPoint, null, null, null); + log.trace("[{}] [{}] Failed to process credentials PSK ", endPoint, e.toString()); + resultSecurityStore[0] = createSecurityInfo(endPoint, null, null); latch.countDown(); } }); try { latch.await(contextS.getCtxServer().getTimeout(), TimeUnit.MILLISECONDS); } catch (InterruptedException e) { - e.printStackTrace(); + log.error("", e); } return resultSecurityStore[0]; } - private ReadResultSecurityStore putSecurityInfo(String endPoint, String deviceName, String jsonStr, TypeServer keyValue) { + /** + * Create new SecurityInfo + * @param endPoint - + * @param jsonStr - + * @param keyValue - + * @return SecurityInfo + */ + private ReadResultSecurityStore createSecurityInfo(String endPoint, String jsonStr, TypeServer keyValue) { ReadResultSecurityStore result = new ReadResultSecurityStore(); JsonObject objectMsg = LwM2MTransportHandler.validateJson(jsonStr); if (objectMsg != null && !objectMsg.isJsonNull()) { @@ -103,20 +115,21 @@ public class LwM2MGetSecurityInfo { if (keyValue.equals(TypeServer.BOOTSTRAP)) { result.setBootstrapJsonCredential(object); result.setEndPoint(endPoint); + result.setSecurityMode(LwM2MSecurityMode.fromSecurityMode(object.get("bootstrapServer").getAsJsonObject().get("securityMode").getAsString().toLowerCase()).code); } else { LwM2MSecurityMode lwM2MSecurityMode = LwM2MSecurityMode.fromSecurityMode(object.get("securityConfigClientMode").getAsString().toLowerCase()); switch (lwM2MSecurityMode) { case NO_SEC: - getClientSecurityInfoNoSec(result); + createClientSecurityInfoNoSec(result); break; case PSK: - getClientSecurityInfoPSK(result, endPoint, object); + createClientSecurityInfoPSK(result, endPoint, object); break; case RPK: - getClientSecurityInfoRPK(result, endPoint, object); + createClientSecurityInfoRPK(result, endPoint, object); break; case X509: - getClientSecurityInfoX509(result, endPoint); + createClientSecurityInfoX509(result, endPoint); break; default: break; @@ -127,12 +140,12 @@ public class LwM2MGetSecurityInfo { return result; } - private void getClientSecurityInfoNoSec(ReadResultSecurityStore result) { + private void createClientSecurityInfoNoSec(ReadResultSecurityStore result) { result.setSecurityInfo(null); result.setSecurityMode(NO_SEC.code); } - private void getClientSecurityInfoPSK(ReadResultSecurityStore result, String endPoint, JsonObject object) { + private void createClientSecurityInfoPSK(ReadResultSecurityStore result, String endPoint, JsonObject object) { /** PSK Deserialization */ String identity = (object.has("identity") && object.get("identity").isJsonPrimitive()) ? object.get("identity").getAsString() : null; if (identity != null && !identity.isEmpty()) { @@ -152,7 +165,7 @@ public class LwM2MGetSecurityInfo { } } - private void getClientSecurityInfoRPK(ReadResultSecurityStore result, String endpoint, JsonObject object) { + private void createClientSecurityInfoRPK(ReadResultSecurityStore result, String endpoint, JsonObject object) { try { if (object.has("key") && object.get("key").isJsonPrimitive()) { byte[] rpkkey = Hex.decodeHex(object.get("key").getAsString().toLowerCase().toCharArray()); @@ -167,7 +180,7 @@ public class LwM2MGetSecurityInfo { } } - private void getClientSecurityInfoX509(ReadResultSecurityStore result, String endpoint) { + private void createClientSecurityInfoX509(ReadResultSecurityStore result, String endpoint) { result.setSecurityInfo(SecurityInfo.newX509CertInfo(endpoint)); result.setSecurityMode(X509.code); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MSessionMsgListener.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MSessionMsgListener.java index 97963038b8..7c3450486e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MSessionMsgListener.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MSessionMsgListener.java @@ -33,10 +33,10 @@ import java.util.Optional; @Slf4j public class LwM2MSessionMsgListener implements GenericFutureListener>, SessionMsgListener { - private LwM2MTransportService service; + private LwM2MTransportServiceImpl service; private TransportProtos.SessionInfoProto sessionInfo; - public LwM2MSessionMsgListener(LwM2MTransportService service, TransportProtos.SessionInfoProto sessionInfo) { + public LwM2MSessionMsgListener(LwM2MTransportServiceImpl service, TransportProtos.SessionInfoProto sessionInfo) { this.service = service; this.sessionInfo = sessionInfo; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportHandler.java index 14d06eb7e6..76cc2a8015 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportHandler.java @@ -31,20 +31,14 @@ 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.util.Hex; -import org.eclipse.leshan.server.californium.LeshanServer; import org.eclipse.leshan.server.californium.LeshanServerBuilder; import org.nustaq.serialization.FSTConfiguration; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; -import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.common.transport.TransportServiceCallback; import org.thingsboard.server.transport.lwm2m.server.client.AttrTelemetryObserveValue; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; -import javax.annotation.PostConstruct; import java.io.File; import java.io.IOException; import java.util.Arrays; @@ -53,8 +47,8 @@ import java.util.LinkedList; import java.util.Optional; @Slf4j -@Component("LwM2MTransportHandler") -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' )|| ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") +//@Component("LwM2MTransportHandler") +//@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' )|| ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") public class LwM2MTransportHandler { // We choose a default timeout a bit higher to the MAX_TRANSMIT_WAIT(62-93s) which is the time from starting to @@ -114,32 +108,38 @@ public class LwM2MTransportHandler { public static final String SERVICE_CHANNEL = "SERVICE"; public static final String RESPONSE_CHANNEL = "RESP"; - @Autowired - @Qualifier("LeshanServerCert") - private LeshanServer lhServerCert; +// @Autowired +// @Qualifier("LeshanServerCert") +// private LeshanServer lhServerCert; +// +// @Autowired +// @Qualifier("LeshanServerNoSecPskRpk") +// private LeshanServer lhServerNoSecPskRpk; - @Autowired - @Qualifier("leshanServerNoSecPskRpk") - private LeshanServer lhServerNoSecPskRpk; +// @Autowired +// @Qualifier("ServerListenerCert") +// private LwM2mServerListener serverListenerCert; +// +// @Autowired +// @Qualifier("ServerListenerNoSecPskRpk") +// private LwM2mServerListener serverListenerNoSecPskRpk; - @Autowired - private LwM2MTransportService service; - @PostConstruct - public void init() { - try { - LwM2mServerListener lwM2mServerListener = new LwM2mServerListener(lhServerCert, service); - this.lhServerCert.getRegistrationService().addListener(lwM2mServerListener.registrationListener); - this.lhServerCert.getPresenceService().addListener(lwM2mServerListener.presenceListener); - this.lhServerCert.getObservationService().addListener(lwM2mServerListener.observationListener); - lwM2mServerListener = new LwM2mServerListener(lhServerNoSecPskRpk, service); - this.lhServerNoSecPskRpk.getRegistrationService().addListener(lwM2mServerListener.registrationListener); - this.lhServerNoSecPskRpk.getPresenceService().addListener(lwM2mServerListener.presenceListener); - this.lhServerNoSecPskRpk.getObservationService().addListener(lwM2mServerListener.observationListener); - } catch (java.lang.NullPointerException e) { - log.error("init [{}]", e.toString()); - } - } +// @PostConstruct +// public void init() { +// try { +// serverListenerCert.init(lhServerCert); +// this.lhServerCert.getRegistrationService().addListener(serverListenerCert.registrationListener); +// this.lhServerCert.getPresenceService().addListener(serverListenerCert.presenceListener); +// this.lhServerCert.getObservationService().addListener(serverListenerCert.observationListener); +// serverListenerNoSecPskRpk.init(lhServerNoSecPskRpk); +// this.lhServerNoSecPskRpk.getRegistrationService().addListener(serverListenerNoSecPskRpk.registrationListener); +// this.lhServerNoSecPskRpk.getPresenceService().addListener(serverListenerNoSecPskRpk.presenceListener); +// this.lhServerNoSecPskRpk.getObservationService().addListener(serverListenerNoSecPskRpk.observationListener); +// } catch (Exception e) { +// log.error("init [{}]", e.toString()); +// } +// } public static NetworkConfig getCoapConfig() { NetworkConfig coapConfig; @@ -217,7 +217,7 @@ public class LwM2MTransportHandler { JsonObject objectMsg = (observeAttrStr != null) ? validateJson(observeAttrStr) : null; return (getValidateCredentialsBodyFromThingsboard(objectMsg)) ? objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject() : null; } catch (IOException e) { - e.printStackTrace(); + log.error("", e); } } return null; @@ -232,7 +232,7 @@ public class LwM2MTransportHandler { JsonObject objectMsg = (bootstrapStr != null) ? validateJson(bootstrapStr) : null; return (getValidateBootstrapProfileFromThingsboard(objectMsg)) ? objectMsg.get(BOOTSTRAP).getAsJsonObject() : null; } catch (IOException e) { - e.printStackTrace(); + log.error("", e); } } return null; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java index 5ee37ac380..bc7cbd5b46 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java @@ -86,7 +86,7 @@ public class LwM2MTransportRequest { private LwM2mValueConverterImpl converter; @Autowired - LwM2MTransportService service; + LwM2MTransportServiceImpl service; @PostConstruct diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerConfiguration.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerConfiguration.java index c17400ede8..ac2221054c 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerConfiguration.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerConfiguration.java @@ -20,10 +20,16 @@ import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeDecoder; import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeEncoder; import org.eclipse.leshan.core.node.codec.LwM2mNodeDecoder; +import org.eclipse.leshan.core.util.Hex; import org.eclipse.leshan.server.californium.LeshanServer; import org.eclipse.leshan.server.californium.LeshanServerBuilder; import org.eclipse.leshan.server.model.LwM2mModelProvider; import org.eclipse.leshan.server.model.VersionedModelProvider; +import org.eclipse.leshan.server.redis.RedisRegistrationStore; +import org.eclipse.leshan.server.redis.RedisSecurityStore; +import org.eclipse.leshan.server.security.DefaultAuthorizer; +import org.eclipse.leshan.server.security.EditableSecurityStore; +import org.eclipse.leshan.server.security.SecurityChecker; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.context.annotation.Bean; @@ -31,11 +37,33 @@ import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode; -import org.thingsboard.server.transport.lwm2m.server.secure.LwM2MSetSecurityStoreServer; import org.thingsboard.server.transport.lwm2m.server.secure.LwM2mInMemorySecurityStore; import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; -import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.X509; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPool; +import redis.clients.jedis.util.Pool; + +import java.math.BigInteger; +import java.net.URI; +import java.net.URISyntaxException; +import java.security.AlgorithmParameters; +import java.security.GeneralSecurityException; +import java.security.KeyFactory; +import java.security.KeyStoreException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.X509Certificate; +import java.security.interfaces.ECPublicKey; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPoint; +import java.security.spec.ECPrivateKeySpec; +import java.security.spec.ECPublicKeySpec; +import java.security.spec.KeySpec; +import java.util.Arrays; + import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.RPK; +import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.X509; import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.getCoapConfig; @@ -45,6 +73,8 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandle @Configuration("LwM2MTransportServerConfiguration") @ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' ) || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") public class LwM2MTransportServerConfiguration { + private PublicKey publicKey; + private PrivateKey privateKey; @Autowired private LwM2MTransportContextServer context; @@ -52,14 +82,26 @@ public class LwM2MTransportServerConfiguration { @Autowired private LwM2mInMemorySecurityStore lwM2mInMemorySecurityStore; + @Bean + public LwM2mServerListener lwM2mServerListenerCert() { + return new LwM2mServerListener(); + } + + @Bean + public LwM2mServerListener lwM2mServerListenerNoSecPskRpk() { + return new LwM2mServerListener(); + } + @Primary @Bean(name = "LeshanServerCert") public LeshanServer getLeshanServerCert() { log.info("Starting LwM2M transport ServerCert... PostConstruct"); - return getLeshanServer(this.context.getCtxServer().getServerPortCert(), this.context.getCtxServer().getServerSecurePortCert(), X509); + LeshanServer leshanServerCert = getLeshanServer(this.context.getCtxServer().getServerPortCert(), this.context.getCtxServer().getServerSecurePortCert(), X509); + + return leshanServerCert; } - @Bean(name = "leshanServerNoSecPskRpk") + @Bean(name = "LeshanServerNoSecPskRpk") public LeshanServer getLeshanServerNoSecPskRpk() { log.info("Starting LwM2M transport ServerNoSecPskRpk... PostConstruct"); return getLeshanServer(this.context.getCtxServer().getServerPort(), this.context.getCtxServer().getServerSecurePort(), RPK); @@ -94,9 +136,178 @@ public class LwM2MTransportServerConfiguration { /** Create DTLS security mode * There can be only one DTLS security mode */ - new LwM2MSetSecurityStoreServer(builder, context, lwM2mInMemorySecurityStore, dtlsMode); + this.LwM2MSetSecurityStoreServer(builder, dtlsMode); /** Create LWM2M server */ return builder.build(); } + + private void LwM2MSetSecurityStoreServer(LeshanServerBuilder builder, LwM2MSecurityMode dtlsMode) { + /** Set securityStore with new registrationStore */ + EditableSecurityStore securityStore = lwM2mInMemorySecurityStore; + + switch (dtlsMode) { + /** Use PSK only */ + case PSK: + generatePSK_RPK(); + if (this.privateKey != null && this.privateKey.getEncoded().length > 0) { + builder.setPrivateKey(this.privateKey); + builder.setPublicKey(null); + infoParamsPSK(); + } + break; + /** Use RPK only */ + case RPK: + generatePSK_RPK(); + if (this.publicKey != null && this.publicKey.getEncoded().length > 0 && + this.privateKey != null && this.privateKey.getEncoded().length > 0) { + builder.setPublicKey(this.publicKey); + builder.setPrivateKey(this.privateKey); + infoParamsRPK(); + } + break; + /** Use x509 only */ + case X509: + setServerWithX509Cert(builder); + break; + /** No security */ + case NO_SEC: + builder.setTrustedCertificates(new X509Certificate[0]); + break; + /** Use x509 with EST */ + case X509_EST: + // TODO support sentinel pool and make pool configurable + break; + case REDIS: + /** + * Set securityStore with new registrationStore (if use redis store) + * Connect to redis + */ + Pool jedis = null; + try { + jedis = new JedisPool(new URI(this.context.getCtxServer().getRedisUrl())); + securityStore = new RedisSecurityStore(jedis); + builder.setRegistrationStore(new RedisRegistrationStore(jedis)); + } catch (URISyntaxException e) { + log.error("", e); + } + break; + default: + } + + /** Set securityStore with registrationStore (if x509)*/ + if (dtlsMode == X509) { + builder.setAuthorizer(new DefaultAuthorizer(securityStore, new SecurityChecker() { + @Override + protected boolean matchX509Identity(String endpoint, String receivedX509CommonName, + String expectedX509CommonName) { + return endpoint.startsWith(expectedX509CommonName); + } + })); + } + + /** Set securityStore with new registrationStore */ + builder.setSecurityStore(securityStore); + } + + private void generatePSK_RPK() { + try { + /** Get Elliptic Curve Parameter spec for secp256r1 */ + AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC"); + algoParameters.init(new ECGenParameterSpec("secp256r1")); + ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class); + if (this.context.getCtxServer().getServerPublicX() != null && !this.context.getCtxServer().getServerPublicX().isEmpty() && this.context.getCtxServer().getServerPublicY() != null && !this.context.getCtxServer().getServerPublicY().isEmpty()) { + /** Get point values */ + byte[] publicX = Hex.decodeHex(this.context.getCtxServer().getServerPublicX().toCharArray()); + byte[] publicY = Hex.decodeHex(this.context.getCtxServer().getServerPublicY().toCharArray()); + /** Create key specs */ + KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)), + parameterSpec); + /** Get keys */ + this.publicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec); + } + if (this.context.getCtxServer().getServerPrivateS() != null && !this.context.getCtxServer().getServerPrivateS().isEmpty()) { + /** Get point values */ + byte[] privateS = Hex.decodeHex(this.context.getCtxServer().getServerPrivateS().toCharArray()); + /** Create key specs */ + KeySpec privateKeySpec = new ECPrivateKeySpec(new BigInteger(privateS), parameterSpec); + /** Get keys */ + this.privateKey = KeyFactory.getInstance("EC").generatePrivate(privateKeySpec); + } + } catch (GeneralSecurityException | IllegalArgumentException e) { + log.error("[{}] Failed generate Server PSK/RPK", e.getMessage()); + throw new RuntimeException(e); + } + } + + private void infoParamsPSK() { + log.info("\nServer uses PSK -> private key : \n security key : [{}] \n serverSecureURI : [{}]", + Hex.encodeHexString(this.privateKey.getEncoded()), + this.context.getCtxServer().getServerSecureHost() + ":" + Integer.toString(this.context.getCtxServer().getServerSecurePort())); + } + + private void infoParamsRPK() { + if (this.publicKey instanceof ECPublicKey) { + /** Get x coordinate */ + byte[] x = ((ECPublicKey) this.publicKey).getW().getAffineX().toByteArray(); + if (x[0] == 0) + x = Arrays.copyOfRange(x, 1, x.length); + + /** Get Y coordinate */ + byte[] y = ((ECPublicKey) this.publicKey).getW().getAffineY().toByteArray(); + if (y[0] == 0) + y = Arrays.copyOfRange(y, 1, y.length); + + /** Get Curves params */ + String params = ((ECPublicKey) this.publicKey).getParams().toString(); + log.info( + " \nServer uses RPK : \n Elliptic Curve parameters : [{}] \n Public x coord : [{}] \n Public y coord : [{}] \n Public Key (Hex): [{}] \n Private Key (Hex): [{}]", + params, Hex.encodeHexString(x), Hex.encodeHexString(y), + Hex.encodeHexString(this.publicKey.getEncoded()), + Hex.encodeHexString(this.privateKey.getEncoded())); + } else { + throw new IllegalStateException("Unsupported Public Key Format (only ECPublicKey supported)."); + } + } + + + private void setServerWithX509Cert(LeshanServerBuilder builder) { + try { + if (this.context.getCtxServer().getKeyStoreValue() != null) { + setBuilderX509(builder); + X509Certificate rootCAX509Cert = (X509Certificate) this.context.getCtxServer().getKeyStoreValue().getCertificate(this.context.getCtxServer().getRootAlias()); + if (rootCAX509Cert != null) { + X509Certificate[] trustedCertificates = new X509Certificate[1]; + trustedCertificates[0] = rootCAX509Cert; + builder.setTrustedCertificates(trustedCertificates); + } else { + /** by default trust all */ + builder.setTrustedCertificates(new X509Certificate[0]); + } + } else { + /** by default trust all */ + builder.setTrustedCertificates(new X509Certificate[0]); + log.error("Unable to load X509 files for LWM2MServer"); + } + } catch (KeyStoreException ex) { + log.error("[{}] Unable to load X509 files server", ex.getMessage()); + } + } + + private void setBuilderX509(LeshanServerBuilder builder) { + /** + * For deb => KeyStorePathFile == yml or commandline: KEY_STORE_PATH_FILE + * For idea => KeyStorePathResource == common/transport/lwm2m/src/main/resources/credentials: in LwM2MTransportContextServer: credentials/serverKeyStore.jks + */ + try { + X509Certificate serverCertificate = (X509Certificate) this.context.getCtxServer().getKeyStoreValue().getCertificate(this.context.getCtxServer().getServerAlias()); + PrivateKey privateKey = (PrivateKey) this.context.getCtxServer().getKeyStoreValue().getKey(this.context.getCtxServer().getServerAlias(), this.context.getCtxServer().getKeyStorePasswordServer() == null ? null : this.context.getCtxServer().getKeyStorePasswordServer().toCharArray()); + builder.setPrivateKey(privateKey); + builder.setCertificateChain(new X509Certificate[]{serverCertificate}); + } catch (Exception ex) { + log.error("[{}] Unable to load KeyStore files server", ex.getMessage()); + } + } + + } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerInitializer.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerInitializer.java index 4a43407a73..36d39130a3 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerInitializer.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerInitializer.java @@ -20,14 +20,15 @@ import org.eclipse.leshan.server.californium.LeshanServer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; -import org.springframework.stereotype.Service; +import org.springframework.stereotype.Component; import org.thingsboard.server.transport.lwm2m.secure.LWM2MGenerationPSkRPkECC; import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode; + import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @Slf4j -@Service("LwM2MTransportServerInitializer") +@Component("LwM2MTransportServerInitializer") @ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' ) || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") public class LwM2MTransportServerInitializer { @@ -36,8 +37,18 @@ public class LwM2MTransportServerInitializer { private LeshanServer lhServerCert; @Autowired - @Qualifier("leshanServerNoSecPskRpk") + @Qualifier("LeshanServerNoSecPskRpk") private LeshanServer lhServerNoSecPskRpk; +// +// @Autowired +// @Qualifier("LeshanServerListener") +// private LwM2mServerListener lwM2mServerListener; + + @Autowired + private LwM2mServerListener lwM2mServerListenerNoSecPskRpk; + + @Autowired + private LwM2mServerListener lwM2mServerListenerCert; @Autowired private LwM2MTransportContextServer context; @@ -46,19 +57,33 @@ public class LwM2MTransportServerInitializer { public void init() { if (this.context.getCtxServer().getEnableGenPskRpk()) new LWM2MGenerationPSkRPkECC(); if (this.context.getCtxServer().isServerStartAll()) { - this.lhServerCert.start(); - this.lhServerNoSecPskRpk.start(); - } - else { + this.startLhServerCert(); + this.startLhServerNoSecPskRpk(); + } else { if (this.context.getCtxServer().getServerDtlsMode() == LwM2MSecurityMode.X509.code) { - this.lhServerCert.start(); - } - else { - this.lhServerNoSecPskRpk.start(); + this.startLhServerCert(); + } else { + this.startLhServerNoSecPskRpk(); } } } + private void startLhServerCert() { + this.lhServerCert.start(); + LwM2mServerListener serverListenerCert = this.lwM2mServerListenerCert.init(this.lhServerCert); + this.lhServerCert.getRegistrationService().addListener(serverListenerCert.registrationListener); + this.lhServerCert.getPresenceService().addListener(serverListenerCert.presenceListener); + this.lhServerCert.getObservationService().addListener(serverListenerCert.observationListener); + } + + private void startLhServerNoSecPskRpk() { + this.lhServerNoSecPskRpk.start(); + LwM2mServerListener serverListenerNoSecPskRpk = this.lwM2mServerListenerNoSecPskRpk.init(this.lhServerNoSecPskRpk); + this.lhServerNoSecPskRpk.getRegistrationService().addListener(serverListenerNoSecPskRpk.registrationListener); + this.lhServerNoSecPskRpk.getPresenceService().addListener(serverListenerNoSecPskRpk.presenceListener); + this.lhServerNoSecPskRpk.getObservationService().addListener(serverListenerNoSecPskRpk.observationListener); + } + @PreDestroy public void shutdown() { log.info("Stopping LwM2M transport Server!"); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java index 9b082ce09f..a9fcbcb669 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java @@ -15,1114 +15,42 @@ */ package org.thingsboard.server.transport.lwm2m.server; -import com.google.gson.Gson; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import lombok.extern.slf4j.Slf4j; -import org.eclipse.leshan.core.model.ResourceModel; -import org.eclipse.leshan.core.node.LwM2mMultipleResource; -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.observation.Observation; -import org.eclipse.leshan.core.request.ContentFormat; -import org.eclipse.leshan.core.request.WriteRequest; import org.eclipse.leshan.core.response.ReadResponse; -import org.eclipse.leshan.core.util.NamedThreadFactory; import org.eclipse.leshan.server.californium.LeshanServer; import org.eclipse.leshan.server.registration.Registration; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; -import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; -import org.thingsboard.server.common.transport.TransportService; -import org.thingsboard.server.common.transport.adaptor.AdaptorException; -import org.thingsboard.server.common.transport.adaptor.JsonConverter; -import org.thingsboard.server.common.transport.service.DefaultTransportService; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.gen.transport.TransportProtos.SessionEvent; -import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; -import org.thingsboard.server.gen.transport.TransportProtos.ToTransportUpdateCredentialsProto; -import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; -import org.thingsboard.server.transport.lwm2m.server.client.AttrTelemetryObserveValue; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; -import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue; -import org.thingsboard.server.transport.lwm2m.server.client.ResultsAnalyzerParameters; -import org.thingsboard.server.transport.lwm2m.server.secure.LwM2mInMemorySecurityStore; -import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; -import javax.annotation.PostConstruct; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; import java.util.Optional; -import java.util.Random; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.stream.Collectors; -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.DEFAULT_TIMEOUT; -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_OBSERVE; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.GET_TYPE_OPER_READ; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.LOG_LW2M_ERROR; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.LOG_LW2M_INFO; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.LOG_LW2M_TELEMETRY; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.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.SERVICE_CHANNEL; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.getAckCallback; +public interface LwM2MTransportService { -@Slf4j -@Service("LwM2MTransportService") -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' ) || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") -public class LwM2MTransportService { + void onRegistered(LeshanServer lwServer, Registration registration, Collection previousObsersations); - private ExecutorService executorRegistered; - private ExecutorService executorUpdateRegistered; - private ExecutorService executorUnRegistered; - private LwM2mValueConverterImpl converter; + void updatedReg(LeshanServer lwServer, Registration registration); + void unReg(Registration registration, Collection observations); - @Autowired - private TransportService transportService; + void onSleepingDev(Registration registration); - @Autowired - public LwM2MTransportContextServer context; + void setCancelObservations(LeshanServer lwServer, Registration registration); - @Autowired - private LwM2MTransportRequest lwM2MTransportRequest; + void setCancelObservationRecourse(LeshanServer lwServer, Registration registration, String path); - @Autowired - LwM2mInMemorySecurityStore lwM2mInMemorySecurityStore; + void onObservationResponse(Registration registration, String path, ReadResponse response); - @PostConstruct - public void init() { - this.context.getScheduler().scheduleAtFixedRate(this::checkInactivityAndReportActivity, new Random().nextInt((int) context.getCtxServer().getSessionReportTimeout()), context.getCtxServer().getSessionReportTimeout(), TimeUnit.MILLISECONDS); - this.executorRegistered = Executors.newCachedThreadPool( - new NamedThreadFactory(String.format("LwM2M %s channel registered", SERVICE_CHANNEL))); - this.executorUpdateRegistered = Executors.newCachedThreadPool( - new NamedThreadFactory(String.format("LwM2M %s channel update registered", SERVICE_CHANNEL))); - this.executorUnRegistered = Executors.newCachedThreadPool( - new NamedThreadFactory(String.format("LwM2M %s channel un registered", SERVICE_CHANNEL))); - this.converter = LwM2mValueConverterImpl.getInstance(); - } + void onAttributeUpdate(TransportProtos.AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo); - /** - * Start registration device - * Create session: Map, LwM2MClient> - * 1. replaceNewRegistration -> (solving the problem of incorrect termination of the previous session with this endpoint) - * 1.1 When we initialize the registration, we register the session by endpoint. - * 1.2 If the server has incomplete requests (canceling the registration of the previous session), - * delete the previous session only by the previous registration.getId - * 1.2 Add Model (Entity) for client (from registration & observe) by registration.getId - * 1.2 Remove from sessions Model by enpPoint - * Next -> Create new LwM2MClient for current session -> setModelClient... - * - * @param lwServer - LeshanServer - * @param registration - Registration LwM2M Client - * @param previousObsersations - may be null - */ - public void onRegistered(LeshanServer lwServer, Registration registration, Collection previousObsersations) { - executorRegistered.submit(() -> { - try { - log.info("[{}] [{{}] Client: create after Registration", registration.getEndpoint(), registration.getId()); - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.updateInSessionsLwM2MClient(lwServer, registration); - if (lwM2MClient != null) { - lwM2MClient.setLwM2MTransportService(this); - lwM2MClient.setSessionUuid(UUID.randomUUID()); - this.sentLogsToThingsboard(LOG_LW2M_INFO + ": Client Registered", registration); - this.setLwM2MClient(lwServer, registration, lwM2MClient); - SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration); - if (sessionInfo != null) { - lwM2MClient.setDeviceUuid(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB())); - lwM2MClient.setProfileUuid(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); - lwM2MClient.setDeviceName(sessionInfo.getDeviceName()); - lwM2MClient.setDeviceProfileName(sessionInfo.getDeviceType()); - transportService.registerAsyncSession(sessionInfo, new LwM2MSessionMsgListener(this, sessionInfo)); - transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN), null); - transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), null); - this.sentLogsToThingsboard(LOG_LW2M_INFO + ": Client create after Registration", registration); - } else { - log.error("Client: [{}] onRegistered [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); - } - } else { - log.error("Client: [{}] onRegistered [{}] name [{}] lwM2MClient ", registration.getId(), registration.getEndpoint(), null); - } - } catch (Throwable t) { - log.error("[{}] endpoint [{}] error Unable registration.", registration.getEndpoint(), t); - } - }); - } + void onDeviceProfileUpdate(TransportProtos.SessionInfoProto sessionInfo, DeviceProfile deviceProfile); - /** - * if sessionInfo removed from sessions, then new registerAsyncSession - * @param lwServer - LeshanServer - * @param registration - Registration LwM2M Client - */ - public void updatedReg(LeshanServer lwServer, Registration registration) { - executorUpdateRegistered.submit(() -> { - try { - SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration); - if (sessionInfo != null) { - this.checkInactivity(sessionInfo); - log.info("Client: [{}] updatedReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType()); - } else { - log.error("Client: [{}] updatedReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); - } - } catch (Throwable t) { - log.error("[{}] endpoint [{}] error Unable update registration.", registration.getEndpoint(), t); - } - }); - } + void onDeviceUpdate(TransportProtos.SessionInfoProto sessionInfo, Device device, Optional deviceProfileOpt); + void doTrigger(LeshanServer lwServer, Registration registration, String path); - /** - * @param registration - Registration LwM2M Client - * @param observations - All paths observations before unReg - * !!! Warn: if have not finishing unReg, then this operation will be finished on next Client`s connect - */ - public void unReg(Registration registration, Collection observations) { - executorUnRegistered.submit(() -> { - try { - this.sentLogsToThingsboard(LOG_LW2M_INFO + ": Client unRegistration", registration); - this.closeClientSession(registration); - } catch (Throwable t) { - log.error("[{}] endpoint [{}] error Unable un registration.", registration.getEndpoint(), t); - } - }); - } + void doDisconnect(TransportProtos.SessionInfoProto sessionInfo); - private void closeClientSession(Registration registration) { - SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration); - if (sessionInfo != null) { - transportService.deregisterSession(sessionInfo); - this.doCloseSession(sessionInfo); - lwM2mInMemorySecurityStore.delRemoveSessionAndListener(registration.getId()); - if (lwM2mInMemorySecurityStore.getProfiles().size() > 0) { - this.syncSessionsAndProfiles(); - } - log.info("Client close session: [{}] unReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType()); - } else { - log.error("Client close session: [{}] unReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); - } - } - public void onSleepingDev(Registration registration) { - log.info("[{}] [{}] Received endpoint Sleeping version event", registration.getId(), registration.getEndpoint()); - //TODO: associate endpointId with device information. - } - - /** - * Those methods are called by the protocol stage thread pool, this means that execution MUST be done in a short delay, - * * if you need to do long time processing use a dedicated thread pool. - * - * @param registration - - */ - protected void onAwakeDev(Registration registration) { - log.info("[{}] [{}] Received endpoint Awake version event", registration.getId(), registration.getEndpoint()); - //TODO: associate endpointId with device information. - } - - /** - * This method is used to sync with sessions - * Removes a profile if not used in sessions - */ - private void syncSessionsAndProfiles() { - Map profilesClone = lwM2mInMemorySecurityStore.getProfiles().entrySet() - .stream() - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - profilesClone.forEach((k, v) -> { - String registrationId = lwM2mInMemorySecurityStore.getSessions().entrySet() - .stream() - .filter(e -> e.getValue().getProfileUuid().equals(k)) - .findFirst() - .map(Map.Entry::getKey) // return the key of the matching entry if found - .orElse(""); - if (registrationId.isEmpty()) { - lwM2mInMemorySecurityStore.getProfiles().remove(k); - } - }); - } - - /** - * #0 Add new ObjectModel to context - * Create new LwM2MClient for current session -> setModelClient... - * #1 Add all ObjectLinks (instance) to control the process of executing requests to the client - * to get the client model with current values - * #2 Get the client model with current values. Analyze the response in -> lwM2MTransportRequest.sendResponse - * - * @param lwServer - LeshanServer - * @param registration - Registration LwM2M Client - * @param lwM2MClient - object with All parameters off client - */ - private void setLwM2MClient(LeshanServer lwServer, Registration registration, LwM2MClient lwM2MClient) { - Arrays.stream(registration.getObjectLinks()).forEach(url -> { - LwM2mPath pathIds = new LwM2mPath(url.getUrl()); - if (pathIds.isObjectInstance() && !pathIds.isResource()) { - lwM2MClient.getPendingRequests().add(url.getUrl()); - } - }); - // #2 - Arrays.stream(registration.getObjectLinks()).forEach(url -> { - LwM2mPath pathIds = new LwM2mPath(url.getUrl()); - if (pathIds.isObjectInstance() && !pathIds.isResource()) { - lwM2MTransportRequest.sendAllRequest(lwServer, registration, url.getUrl(), GET_TYPE_OPER_READ, ContentFormat.TLV.getName(), - lwM2MClient, null, null, this.context.getCtxServer().getTimeout(), false); - } - }); - } - - /** - * @param registration - Registration LwM2M Client - * @return - sessionInfo after access connect client - */ - private SessionInfoProto getValidateSessionInfo(Registration registration) { - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClientWithReg(registration, null); - return getNewSessionInfoProto(lwM2MClient); - - } - - /** - * - * @param registrationId - - * @return - - */ - private SessionInfoProto getValidateSessionInfo(String registrationId) { - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClientWithReg(null, registrationId); - return getNewSessionInfoProto(lwM2MClient); - } - - private SessionInfoProto getNewSessionInfoProto(LwM2MClient lwM2MClient) { - if (lwM2MClient != null) { - ValidateDeviceCredentialsResponseMsg msg = lwM2MClient.getCredentialsResponse(); - if (msg == null || msg.getDeviceInfo() == null) { - log.error("[{}] [{}]", lwM2MClient.getEndPoint(), CLIENT_NOT_AUTHORIZED); - this.closeClientSession(lwM2MClient.getRegistration()); - return null; - } else { - return SessionInfoProto.newBuilder() - .setNodeId(this.context.getNodeId()) - .setSessionIdMSB(lwM2MClient.getSessionUuid().getMostSignificantBits()) - .setSessionIdLSB(lwM2MClient.getSessionUuid().getLeastSignificantBits()) - .setDeviceIdMSB(msg.getDeviceInfo().getDeviceIdMSB()) - .setDeviceIdLSB(msg.getDeviceInfo().getDeviceIdLSB()) - .setTenantIdMSB(msg.getDeviceInfo().getTenantIdMSB()) - .setTenantIdLSB(msg.getDeviceInfo().getTenantIdLSB()) - .setDeviceName(msg.getDeviceInfo().getDeviceName()) - .setDeviceType(msg.getDeviceInfo().getDeviceType()) - .setDeviceProfileIdLSB(msg.getDeviceInfo().getDeviceProfileIdLSB()) - .setDeviceProfileIdMSB(msg.getDeviceInfo().getDeviceProfileIdMSB()) - .build(); - } - } - return null; - } - - /** - * Add attribute/telemetry information from Client and credentials/Profile to client model and start observe - * !!! if the resource has an observation, but no telemetry or attribute - the observation will not use - * #1 Sending Attribute Telemetry with value to thingsboard only once at the start of the connection - * #2 Start observe - * - * @param lwM2MClient - LwM2M Client - */ - - public void updatesAndSentModelParameter(LwM2MClient lwM2MClient) { - // #1 - this.updateAttrTelemetry(lwM2MClient.getRegistration(), true, null); - // #2 - this.onSentObserveToClient(lwM2MClient.getLwServer(), lwM2MClient.getRegistration()); - - } - - /** - * If there is a difference in values between the current resource values and the shared attribute values - * when the client connects to the server - * #1 get attributes name from profile include name resources in ModelObject if resource isWritable - * #2.1 #1 size > 0 => send Request getAttributes to thingsboard - * #2.2 #1 size == 0 => continue normal process - * - * @param lwM2MClient - LwM2M Client - */ - public void putDelayedUpdateResourcesThingsboard(LwM2MClient lwM2MClient) { - SessionInfoProto sessionInfo = this.getValidateSessionInfo(lwM2MClient.getRegistration()); - if (sessionInfo != null) { - //#1.1 + #1.2 - List attrSharedNames = this.getNamesAttrFromProfileIsWritable(lwM2MClient); - if (attrSharedNames.size() > 0) { - //#2.1 - try { - TransportProtos.GetAttributeRequestMsg getAttributeMsg = context.getAdaptor().convertToGetAttributes(null, attrSharedNames); - lwM2MClient.getDelayedRequestsId().add(getAttributeMsg.getRequestId()); - transportService.process(sessionInfo, getAttributeMsg, getAckCallback(lwM2MClient, getAttributeMsg.getRequestId(), DEVICE_ATTRIBUTES_REQUEST)); - } catch (AdaptorException e) { - log.warn("Failed to decode get attributes request", e); - } - } - // #2.2 - else { - lwM2MClient.onSuccessOrErrorDelayedRequests(null); - } - } - } - - /** - * Update resource value on client: if there is a difference in values between the current resource values and the shared attribute values - * #1 Get path resource by result attributesResponse - * #1.1 If two names have equal path => last time attribute - * #2.1 if there is a difference in values between the current resource values and the shared attribute values - * => sent to client Request Update of value (new value from shared attribute) - * and LwM2MClient.delayedRequests.add(path) - * #2.1 if there is not a difference in values between the current resource values and the shared attribute values - * - * @param attributesResponse - - * @param sessionInfo - - */ - public void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg attributesResponse, TransportProtos.SessionInfoProto sessionInfo) { - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(sessionInfo); - if (lwM2MClient.getDelayedRequestsId().contains(attributesResponse.getRequestId())) { - attributesResponse.getSharedAttributeListList().forEach(attr -> { - String path = this.getPathAttributeUpdate(sessionInfo, attr.getKv().getKey()); - // #1.1 - if (lwM2MClient.getDelayedRequests().containsKey(path) && attr.getTs() > lwM2MClient.getDelayedRequests().get(path).getTs()) { - lwM2MClient.getDelayedRequests().put(path, attr); - } else { - lwM2MClient.getDelayedRequests().put(path, attr); - } - }); - // #2.1 - lwM2MClient.getDelayedRequests().forEach((k, v) -> { - ArrayList listV = new ArrayList<>(); - listV.add(v.getKv()); - this.putDelayedUpdateResourcesClient(lwM2MClient, this.getResourceValueToString(lwM2MClient, k), getJsonObject(listV).get(v.getKv().getKey()), k); - }); - lwM2MClient.getDelayedRequestsId().remove(attributesResponse.getRequestId()); - if (lwM2MClient.getDelayedRequests().size() == 0) { - lwM2MClient.onSuccessOrErrorDelayedRequests(null); - } - } - } - - private void putDelayedUpdateResourcesClient(LwM2MClient lwM2MClient, Object valueOld, Object valueNew, String path) { - if (valueNew != null && !valueNew.toString().equals(valueOld.toString())) { - lwM2MTransportRequest.sendAllRequest(lwM2MClient.getLwServer(), lwM2MClient.getRegistration(), path, POST_TYPE_OPER_WRITE_REPLACE, - ContentFormat.TLV.getName(), lwM2MClient, null, valueNew, this.context.getCtxServer().getTimeout(), - true); - } - } - - /** - * Get names and keyNames from profile shared!!!! attr resources IsWritable - * @param lwM2MClient - - * @return ArrayList keyNames from profile attr resources shared!!!! && IsWritable - */ - private List getNamesAttrFromProfileIsWritable(LwM2MClient lwM2MClient) { - AttrTelemetryObserveValue profile = lwM2mInMemorySecurityStore.getProfile(lwM2MClient.getProfileUuid()); - Set attrSet = new Gson().fromJson(profile.getPostAttributeProfile(), Set.class); - ConcurrentMap keyNamesMap = new Gson().fromJson(profile.getPostKeyNameProfile().toString(), ConcurrentHashMap.class); - - ConcurrentMap keyNamesIsWritable = keyNamesMap.entrySet() - .stream() - .filter(e -> (attrSet.contains(e.getKey()) && context.getCtxServer().getResourceModel(lwM2MClient.getRegistration(), new LwM2mPath(e.getKey())) != null && - context.getCtxServer().getResourceModel(lwM2MClient.getRegistration(), new LwM2mPath(e.getKey())).operations.isWritable())) - .collect(Collectors.toConcurrentMap(Map.Entry::getKey, Map.Entry::getValue)); - - Set namesIsWritable = ConcurrentHashMap.newKeySet(); - namesIsWritable.addAll(new HashSet<>(keyNamesIsWritable.values())); - return new ArrayList<>(namesIsWritable); - } - - - /** - * Sent Attribute and Telemetry to Thingsboard - * #1 - get AttrName/TelemetryName with value: - * #1.1 from Client - * #1.2 from LwM2MClient: - * -- resourceId == path from AttrTelemetryObserveValue.postAttributeProfile/postTelemetryProfile/postObserveProfile - * -- AttrName/TelemetryName == resourceName from ModelObject.objectModel, value from ModelObject.instance.resource(resourceId) - * #2 - set Attribute/Telemetry - * - * @param registration - Registration LwM2M Client - */ - private void updateAttrTelemetry(Registration registration, boolean start, Set paths) { - JsonObject attributes = new JsonObject(); - JsonObject telemetries = new JsonObject(); - if (start) { - // #1.1 - JsonObject attributeClient = this.getAttributeClient(registration); - if (attributeClient != null) { - attributeClient.entrySet().forEach(p -> attributes.add(p.getKey(), p.getValue())); - } - } - // #1.2 - CountDownLatch cancelLatch = new CountDownLatch(1); - this.getParametersFromProfile(attributes, telemetries, registration, paths); - cancelLatch.countDown(); - try { - cancelLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - log.error("[{}] updateAttrTelemetry", e.toString()); - } - if (attributes.getAsJsonObject().entrySet().size() > 0) - this.updateParametersOnThingsboard(attributes, DEVICE_ATTRIBUTES_TOPIC, registration); - if (telemetries.getAsJsonObject().entrySet().size() > 0) - this.updateParametersOnThingsboard(telemetries, DEVICE_TELEMETRY_TOPIC, registration); - } - - /** - * get AttrName/TelemetryName with value from Client - * - * @param registration - - * @return - JsonObject, format: {name: value}} - */ - private JsonObject getAttributeClient(Registration registration) { - if (registration.getAdditionalRegistrationAttributes().size() > 0) { - JsonObject resNameValues = new JsonObject(); - registration.getAdditionalRegistrationAttributes().forEach(resNameValues::addProperty); - return resNameValues; - } - return null; - } - - /** - * @param attributes - new JsonObject - * @param telemetry - new JsonObject - * @param registration - Registration LwM2M Client - * result: add to JsonObject those resources to which the user is subscribed and they have a value - * if path==null add All resources else only one - * (attributes/telemetry): new {name(Attr/Telemetry):value} - */ - private void getParametersFromProfile(JsonObject attributes, JsonObject telemetry, Registration registration, Set path) { - AttrTelemetryObserveValue attrTelemetryObserveValue = lwM2mInMemorySecurityStore.getProfiles().get(lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getProfileUuid()); - attrTelemetryObserveValue.getPostAttributeProfile().forEach(p -> { - LwM2mPath pathIds = new LwM2mPath(p.getAsString().toString()); - if (pathIds.isResource()) { - if (path == null || path.contains(p.getAsString())) { - this.addParameters(p.getAsString().toString(), attributes, registration); - } - } - }); - attrTelemetryObserveValue.getPostTelemetryProfile().forEach(p -> { - LwM2mPath pathIds = new LwM2mPath(p.getAsString().toString()); - if (pathIds.isResource()) { - if (path == null || path.contains(p.getAsString())) { - this.addParameters(p.getAsString().toString(), telemetry, registration); - } - } - }); - } - - /** - * @param parameters - JsonObject attributes/telemetry - * @param registration - Registration LwM2M Client - */ - private void addParameters(String path, JsonObject parameters, Registration registration) { - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getSessions().get(registration.getId()); - JsonObject names = lwM2mInMemorySecurityStore.getProfiles().get(lwM2MClient.getProfileUuid()).getPostKeyNameProfile(); - String resName = String.valueOf(names.get(path)); - if (resName != null && !resName.isEmpty()) { - try { - String resValue = this.getResourceValueToString(lwM2MClient, path); - if (resValue != null) { - parameters.addProperty(resName, resValue); - } - } catch (Exception e) { - log.error(e.getStackTrace().toString()); - } - } - } - - /** - * Prepare Sent to Thigsboard callback - Attribute or Telemetry - * - * @param msg - JsonArray: [{name: value}] - * @param topicName - Api Attribute or Telemetry - * @param registration - Id of Registration LwM2M Client - */ - public void updateParametersOnThingsboard(JsonElement msg, String topicName, Registration registration) { - SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration); - if (sessionInfo != null) { - context.sentParametersOnThingsboard(msg, topicName, sessionInfo); - } else { - log.error("Client: [{}] updateParametersOnThingsboard [{}] sessionInfo ", registration, null); - } - } - - /** - * Start observe - * #1 - Analyze: - * #1.1 path in observe == (attribute or telemetry) - * #2 Analyze after sent request (response): - * #2.1 First: lwM2MTransportRequest.sendResponse -> ObservationListener.newObservation - * #2.2 Next: ObservationListener.onResponse * - * - * @param lwServer - LeshanServer - * @param registration - Registration LwM2M Client - */ - private void onSentObserveToClient(LeshanServer lwServer, Registration registration) { - if (lwServer.getObservationService().getObservations(registration).size() > 0) { - this.setCancelObservations(lwServer, registration); - } - UUID profileUUid = lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getProfileUuid(); - AttrTelemetryObserveValue attrTelemetryObserveValue = lwM2mInMemorySecurityStore.getProfiles().get(profileUUid); - attrTelemetryObserveValue.getPostObserveProfile().forEach(p -> { - // #1.1 - String target = (getValidateObserve(attrTelemetryObserveValue.getPostAttributeProfile(), p.getAsString().toString())) ? - p.getAsString().toString() : (getValidateObserve(attrTelemetryObserveValue.getPostTelemetryProfile(), p.getAsString().toString())) ? - p.getAsString().toString() : null; - if (target != null) { - // #2 - if (this.getResourceValueToString(lwM2mInMemorySecurityStore.getSessions().get(registration.getId()), target) != null) { - lwM2MTransportRequest.sendAllRequest(lwServer, registration, target, GET_TYPE_OPER_OBSERVE, - null, null, null, null, this.context.getCtxServer().getTimeout(), - false); - } - } - }); - } - - public void setCancelObservations(LeshanServer lwServer, Registration registration) { - if (registration != null) { - Set observations = lwServer.getObservationService().getObservations(registration); - observations.forEach(observation -> this.setCancelObservationRecourse(lwServer, registration, observation.getPath().toString())); - } - } - - /** - * lwM2MTransportRequest.sendAllRequest(lwServer, registration, path, POST_TYPE_OPER_OBSERVE_CANCEL, null, null, null, null, context.getTimeout()); - * At server side this will not remove the observation from the observation store, to do it you need to use - * {@code ObservationService#cancelObservation()} - */ - public void setCancelObservationRecourse(LeshanServer lwServer, Registration registration, String path) { - CountDownLatch cancelLatch = new CountDownLatch(1); - lwServer.getObservationService().cancelObservations(registration, path); - cancelLatch.countDown(); - try { - cancelLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - /** - * @param parameters - JsonArray postAttributeProfile/postTelemetryProfile - * @param path - recourse from postObserveProfile - * @return rez - true if path observe is in attribute/telemetry - */ - private boolean getValidateObserve(JsonElement parameters, String path) { - AtomicBoolean rez = new AtomicBoolean(false); - if (parameters.isJsonArray()) { - parameters.getAsJsonArray().forEach(p -> { - if (p.getAsString().toString().equals(path)) rez.set(true); - } - ); - } else if (parameters.isJsonObject()) { - rez.set((parameters.getAsJsonObject().entrySet()).stream().map(json -> json.toString()) - .filter(path::equals).findAny().orElse(null) != null); - } - return rez.get(); - } - - /** - * Sending observe value to thingsboard from ObservationListener.onResponse: object, instance, SingleResource or MultipleResource - * - * @param registration - Registration LwM2M Client - * @param path - observe - * @param response - observe - */ - - public void onObservationResponse(Registration registration, String path, ReadResponse response) { - if (response.getContent() != null) { - if (response.getContent() instanceof LwM2mObject) { -// LwM2mObject content = (LwM2mObject) response.getContent(); - } else if (response.getContent() instanceof LwM2mObjectInstance) { -// LwM2mObjectInstance content = (LwM2mObjectInstance) response.getContent(); - } else if (response.getContent() instanceof LwM2mSingleResource) { - LwM2mSingleResource content = (LwM2mSingleResource) response.getContent(); - this.onObservationSetResourcesValue(registration, content.getValue(), null, path); - } else if (response.getContent() instanceof LwM2mMultipleResource) { - LwM2mSingleResource content = (LwM2mSingleResource) response.getContent(); - this.onObservationSetResourcesValue(registration, null, content.getValues(), path); - } - } - } - - /** - * Sending observe value of resources to thingsboard - * #1 Return old Value Resource from LwM2MClient - * #2 Update new Resources (replace old Resource Value on new Resource Value) - * - * @param registration - Registration LwM2M Client - * @param value - LwM2mSingleResource response.getContent() - * @param values - LwM2mSingleResource response.getContent() - * @param path - resource - */ - private void onObservationSetResourcesValue(Registration registration, Object value, Map values, String path) { - CountDownLatch respLatch = new CountDownLatch(1); - boolean isChange = false; - try { - // #1 - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClientWithReg(registration, null); - LwM2mPath pathIds = new LwM2mPath(path); - log.warn("#0 nameDevice: [{}] resultIds: [{}] value: [{}], values: [{}] ", lwM2MClient.getDeviceName(), pathIds, value, values); - ResourceModel.Type resModelType = context.getCtxServer().getResourceModelType(registration, pathIds); - ResourceValue resValueOld = lwM2MClient.getResources().get(path); - // #2 - if (resValueOld.isMultiInstances() && !values.toString().equals(resValueOld.getResourceValue().toString())) { - ResourceValue resourceValue = new ResourceValue(values, null, true); - lwM2MClient.getResources().put(path, resourceValue); - isChange = true; - } else if (!LwM2MTransportHandler.equalsResourceValue(resValueOld.getValue(), value, resModelType, pathIds)) { - ResourceValue resourceValue = new ResourceValue(null, value, false); - lwM2MClient.getResources().put(path, resourceValue); - isChange = true; - } - } finally { - respLatch.countDown(); - } - try { - respLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); - } catch (InterruptedException ex) { - ex.printStackTrace(); - log.error("#1_1 Update ResourcesValue after Observation in CountDownLatch is unsuccessfully path: [{}] value: [{}]", path, value); - } - if (isChange) { - Set paths = new HashSet<>(); - paths.add(path); - this.updateAttrTelemetry(registration, false, paths); - } - } - - /** - * @param updateCredentials - Credentials include config only security Client (without config attr/telemetry...) - * config attr/telemetry... in profile - */ - public void onToTransportUpdateCredentials(ToTransportUpdateCredentialsProto updateCredentials) { - log.info("[{}] idList [{}] valueList updateCredentials", updateCredentials.getCredentialsIdList(), updateCredentials.getCredentialsValueList()); - } - - /** - * Update - sent request in change value resources in Client - * Path to resources from profile equal keyName or from ModelObject equal name - * Only for resources: isWritable && isPresent as attribute in profile -> AttrTelemetryObserveValue (format: CamelCase) - * Delete - nothing * - * - * @param msg - - */ - public void onAttributeUpdate(TransportProtos.AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo) { - if (msg.getSharedUpdatedCount() > 0) { - JsonElement el = JsonConverter.toJson(msg); - el.getAsJsonObject().entrySet().forEach(de -> { - String path = this.getPathAttributeUpdate(sessionInfo, de.getKey()); - String value = de.getValue().getAsString(); - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getSession(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())).entrySet().iterator().next().getValue(); - AttrTelemetryObserveValue profile = lwM2mInMemorySecurityStore.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); - ResourceModel resourceModel = context.getCtxServer().getResourceModel(lwM2MClient.getRegistration(), new LwM2mPath(path)); - if (!path.isEmpty() && (this.validatePathInAttrProfile(profile, path) || this.validatePathInTelemetryProfile(profile, path))) { - if (resourceModel != null && resourceModel.operations.isWritable()) { - lwM2MTransportRequest.sendAllRequest(lwM2MClient.getLwServer(), lwM2MClient.getRegistration(), path, POST_TYPE_OPER_WRITE_REPLACE, - ContentFormat.TLV.getName(), lwM2MClient, null, value, this.context.getCtxServer().getTimeout(), - false); - } else { - log.error("Resource path - [{}] value - [{}] is not Writable and cannot be updated", path, value); - String logMsg = String.format(LOG_LW2M_ERROR + ": attributeUpdate: Resource path - %s value - %s is not Writable and cannot be updated", path, value); - this.sentLogsToThingsboard(logMsg, lwM2MClient.getRegistration()); - } - } else { - log.error("Attribute name - [{}] value - [{}] is not present as attribute in profile and cannot be updated", de.getKey(), value); - String logMsg = String.format(LOG_LW2M_ERROR + ": attributeUpdate: attribute name - %s value - %s is not present as attribute in profile and cannot be updated", de.getKey(), value); - this.sentLogsToThingsboard(logMsg, lwM2MClient.getRegistration()); - } - }); - } else if (msg.getSharedDeletedCount() > 0) { - log.info("[{}] delete [{}] onAttributeUpdate", msg.getSharedDeletedList(), sessionInfo); - } - } - - /** - * Get path to resource from profile equal keyName or from ModelObject equal name - * Only for resource: isWritable && isPresent as attribute in profile -> AttrTelemetryObserveValue (format: CamelCase) - * - * @param sessionInfo - - * @param name - - * @return path if path isPresent in postProfile - */ - private String getPathAttributeUpdate(TransportProtos.SessionInfoProto sessionInfo, String name) { - String profilePath = this.getPathAttributeUpdateProfile(sessionInfo, name); -// return !profilePath.isEmpty() ? profilePath : this.getPathAttributeUpdateModelObject(name); - return !profilePath.isEmpty() ? profilePath : null; - } - - /** - * @param profile - - * @param path - - * @return true if path isPresent in postAttributeProfile - */ - private boolean validatePathInAttrProfile(AttrTelemetryObserveValue profile, String path) { - Set attributesSet = new Gson().fromJson(profile.getPostAttributeProfile(), Set.class); - return attributesSet.stream().filter(p -> p.equals(path)).findFirst().isPresent(); - } - - /** - * @param profile - - * @param path - - * @return true if path isPresent in postAttributeProfile - */ - private boolean validatePathInTelemetryProfile(AttrTelemetryObserveValue profile, String path) { - Set telemetriesSet = new Gson().fromJson(profile.getPostTelemetryProfile(), Set.class); - return telemetriesSet.stream().filter(p -> p.equals(path)).findFirst().isPresent(); - } - - - /** - * Get path to resource from profile equal keyName - * - * @param sessionInfo - - * @param name - - * @return - - */ - private String getPathAttributeUpdateProfile(TransportProtos.SessionInfoProto sessionInfo, String name) { - AttrTelemetryObserveValue profile = lwM2mInMemorySecurityStore.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); - return profile.getPostKeyNameProfile().getAsJsonObject().entrySet().stream() - .filter(e -> e.getValue().getAsString().equals(name)).findFirst().map(Map.Entry::getKey) - .orElse(""); - } - - /** - * Update resource (attribute) value on thingsboard after update value in client - * - * @param registration - - * @param path - - * @param request - - */ - public void onAttributeUpdateOk(Registration registration, String path, WriteRequest request, boolean isDelayedUpdate) { - ResourceModel resource = context.getCtxServer().getResourceModel(registration, new LwM2mPath(path)); - if (resource.multiple) { - this.onObservationSetResourcesValue(registration, null, ((LwM2mSingleResource) request.getNode()).getValues(), path); - } else { - this.onObservationSetResourcesValue(registration, ((LwM2mSingleResource) request.getNode()).getValue(), null, path); - } - if (isDelayedUpdate) lwM2mInMemorySecurityStore.getLwM2MClientWithReg(registration, null) - .onSuccessOrErrorDelayedRequests(request.getPath().toString()); - } - - /** - * @param sessionInfo - - * @param deviceProfile - - */ - public void onDeviceProfileUpdate(TransportProtos.SessionInfoProto sessionInfo, DeviceProfile deviceProfile) { - Set registrationIds = lwM2mInMemorySecurityStore.getSessions().entrySet() - .stream() - .filter(e -> e.getValue().getProfileUuid().equals(deviceProfile.getUuidId())) - .map(Map.Entry::getKey).sorted().collect(Collectors.toCollection(LinkedHashSet::new)); - if (registrationIds.size() > 0) { - this.onDeviceUpdateChangeProfile(registrationIds, deviceProfile); - } - } - - /** - * @param sessionInfo - - * @param device - - * @param deviceProfileOpt - - */ - public void onDeviceUpdate(TransportProtos.SessionInfoProto sessionInfo, Device device, Optional deviceProfileOpt) { - Optional registrationIdOpt = lwM2mInMemorySecurityStore.getSessions().entrySet().stream() - .filter(e -> device.getUuidId().equals(e.getValue().getDeviceUuid())) - .map(Map.Entry::getKey) - .findFirst(); - registrationIdOpt.ifPresent(registrationId -> this.onDeviceUpdateLwM2MClient(registrationId, device, deviceProfileOpt)); - } - - /** - * Update parameters device in LwM2MClient - * If new deviceProfile != old deviceProfile => update deviceProfile - * - * @param registrationId - - * @param device - - */ - private void onDeviceUpdateLwM2MClient(String registrationId, Device device, Optional deviceProfileOpt) { - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getSessions().get(registrationId); - lwM2MClient.setDeviceName(device.getName()); - if (!lwM2MClient.getProfileUuid().equals(device.getDeviceProfileId().getId())) { - Set registrationIds = new HashSet<>(); - registrationIds.add(registrationId); - deviceProfileOpt.ifPresent(deviceProfile -> this.onDeviceUpdateChangeProfile(registrationIds, deviceProfile)); - } - - lwM2MClient.setProfileUuid(device.getDeviceProfileId().getId()); - } - - /** - * #1 Read new, old Value (Attribute, Telemetry, Observe, KeyName) - * #2 Update in lwM2MClient: ...Profile if changes from update device - * #3 Equivalence test: old <> new Value (Attribute, Telemetry, Observe, KeyName) - * #3.1 Attribute isChange (add&del) - * #3.2 Telemetry isChange (add&del) - * #3.3 KeyName isChange (add) - * #4 update - * #4.1 add If #3 isChange, then analyze and update Value in Transport form Client and sent Value to thingsboard - * #4.2 del - * -- if add attributes includes del telemetry - result del for observe - * #5 - * #5.1 Observe isChange (add&del) - * #5.2 Observe.add - * -- path Attr/Telemetry includes newObserve and does not include oldObserve: sent Request observe to Client - * #5.3 Observe.del - * -- different between newObserve and oldObserve: sent Request cancel observe to client - * - * @param registrationIds - - * @param deviceProfile - - */ - public void onDeviceUpdateChangeProfile(Set registrationIds, DeviceProfile deviceProfile) { - - AttrTelemetryObserveValue attrTelemetryObserveValueOld = lwM2mInMemorySecurityStore.getProfiles().get(deviceProfile.getUuidId()); - if (lwM2mInMemorySecurityStore.addUpdateProfileParameters(deviceProfile)) { - - // #1 - JsonArray attributeOld = attrTelemetryObserveValueOld.getPostAttributeProfile(); - Set attributeSetOld = new Gson().fromJson(attributeOld, Set.class); - JsonArray telemetryOld = attrTelemetryObserveValueOld.getPostTelemetryProfile(); - Set telemetrySetOld = new Gson().fromJson(telemetryOld, Set.class); - JsonArray observeOld = attrTelemetryObserveValueOld.getPostObserveProfile(); - JsonObject keyNameOld = attrTelemetryObserveValueOld.getPostKeyNameProfile(); - - AttrTelemetryObserveValue attrTelemetryObserveValueNew = lwM2mInMemorySecurityStore.getProfiles().get(deviceProfile.getUuidId()); - JsonArray attributeNew = attrTelemetryObserveValueNew.getPostAttributeProfile(); - Set attributeSetNew = new Gson().fromJson(attributeNew, Set.class); - JsonArray telemetryNew = attrTelemetryObserveValueNew.getPostTelemetryProfile(); - Set telemetrySetNew = new Gson().fromJson(telemetryNew, Set.class); - JsonArray observeNew = attrTelemetryObserveValueNew.getPostObserveProfile(); - JsonObject keyNameNew = attrTelemetryObserveValueNew.getPostKeyNameProfile(); - - // #3 - ResultsAnalyzerParameters sentAttrToThingsboard = new ResultsAnalyzerParameters(); - // #3.1 - if (!attributeOld.equals(attributeNew)) { - ResultsAnalyzerParameters postAttributeAnalyzer = this.getAnalyzerParameters(new Gson().fromJson(attributeOld, Set.class), attributeSetNew); - sentAttrToThingsboard.getPathPostParametersAdd().addAll(postAttributeAnalyzer.getPathPostParametersAdd()); - sentAttrToThingsboard.getPathPostParametersDel().addAll(postAttributeAnalyzer.getPathPostParametersDel()); - } - // #3.2 - if (!attributeOld.equals(attributeNew)) { - ResultsAnalyzerParameters postTelemetryAnalyzer = this.getAnalyzerParameters(new Gson().fromJson(telemetryOld, Set.class), telemetrySetNew); - sentAttrToThingsboard.getPathPostParametersAdd().addAll(postTelemetryAnalyzer.getPathPostParametersAdd()); - sentAttrToThingsboard.getPathPostParametersDel().addAll(postTelemetryAnalyzer.getPathPostParametersDel()); - } - // #3.3 - if (!keyNameOld.equals(keyNameNew)) { - ResultsAnalyzerParameters keyNameChange = this.getAnalyzerKeyName(new Gson().fromJson(keyNameOld.toString(), ConcurrentHashMap.class), - new Gson().fromJson(keyNameNew.toString(), ConcurrentHashMap.class)); - sentAttrToThingsboard.getPathPostParametersAdd().addAll(keyNameChange.getPathPostParametersAdd()); - } - - // #4.1 add - if (sentAttrToThingsboard.getPathPostParametersAdd().size() > 0) { - // update value in Resources - registrationIds.forEach(registrationId -> { - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClientWithReg(null, registrationId); - LeshanServer lwServer = lwM2MClient.getLwServer(); - Registration registration = lwM2mInMemorySecurityStore.getByRegistration(registrationId); - log.warn("[{}] # 4.1", registration.getEndpoint()); - this.updateResourceValueObserve(lwServer, registration, sentAttrToThingsboard.getPathPostParametersAdd(), GET_TYPE_OPER_READ); - // sent attr/telemetry to tingsboard for new path - this.updateAttrTelemetry(registration, false, sentAttrToThingsboard.getPathPostParametersAdd()); - }); - } - // #4.2 del - if (sentAttrToThingsboard.getPathPostParametersDel().size() > 0) { - ResultsAnalyzerParameters sentAttrToThingsboardDel = this.getAnalyzerParameters(sentAttrToThingsboard.getPathPostParametersAdd(), sentAttrToThingsboard.getPathPostParametersDel()); - sentAttrToThingsboard.setPathPostParametersDel(sentAttrToThingsboardDel.getPathPostParametersDel()); - } - - // #5.1 - if (!observeOld.equals(observeNew)) { - Set observeSetOld = new Gson().fromJson(observeOld, Set.class); - Set observeSetNew = new Gson().fromJson(observeNew, Set.class); - //#5.2 add - // path Attr/Telemetry includes newObserve - attributeSetOld.addAll(telemetrySetOld); - ResultsAnalyzerParameters sentObserveToClientOld = this.getAnalyzerParametersIn(attributeSetOld, observeSetOld); // add observe - attributeSetNew.addAll(telemetrySetNew); - ResultsAnalyzerParameters sentObserveToClientNew = this.getAnalyzerParametersIn(attributeSetNew, observeSetNew); // add observe - // does not include oldObserve - ResultsAnalyzerParameters postObserveAnalyzer = this.getAnalyzerParameters(sentObserveToClientOld.getPathPostParametersAdd(), sentObserveToClientNew.getPathPostParametersAdd()); - // sent Request observe to Client - registrationIds.forEach(registrationId -> { - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(null, registrationId); - LeshanServer lwServer = lwM2MClient.getLwServer(); - Registration registration = lwM2mInMemorySecurityStore.getByRegistration(registrationId); - log.warn("[{}] # 5.1", registration.getEndpoint()); - this.updateResourceValueObserve(lwServer, registration, postObserveAnalyzer.getPathPostParametersAdd(), GET_TYPE_OPER_OBSERVE); - // 5.3 del - // sent Request cancel observe to Client - this.cancelObserveIsValue(lwServer, registration, postObserveAnalyzer.getPathPostParametersDel()); - }); - } - } - } - - /** - * Compare old list with new list after change AttrTelemetryObserve in config Profile - * - * @param parametersOld - - * @param parametersNew - - * @return ResultsAnalyzerParameters: add && new - */ - private ResultsAnalyzerParameters getAnalyzerParameters(Set parametersOld, Set parametersNew) { - ResultsAnalyzerParameters analyzerParameters = null; - if (!parametersOld.equals(parametersNew)) { - analyzerParameters = new ResultsAnalyzerParameters(); - analyzerParameters.setPathPostParametersAdd(parametersNew - .stream().filter(p -> !parametersOld.contains(p)).collect(Collectors.toSet())); - analyzerParameters.setPathPostParametersDel(parametersOld - .stream().filter(p -> !parametersNew.contains(p)).collect(Collectors.toSet())); - } - return analyzerParameters; - } - - private ResultsAnalyzerParameters getAnalyzerKeyName(ConcurrentMap keyNameOld, ConcurrentMap keyNameNew) { - ResultsAnalyzerParameters analyzerParameters = new ResultsAnalyzerParameters(); - Set paths = keyNameNew.entrySet() - .stream() - .filter(e -> !e.getValue().equals(keyNameOld.get(e.getKey()))) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)).keySet(); - analyzerParameters.setPathPostParametersAdd(paths); - return analyzerParameters; - } - - private ResultsAnalyzerParameters getAnalyzerParametersIn(Set parametersObserve, Set parameters) { - ResultsAnalyzerParameters analyzerParameters = new ResultsAnalyzerParameters(); - analyzerParameters.setPathPostParametersAdd(parametersObserve - .stream().filter(parameters::contains).collect(Collectors.toSet())); - return analyzerParameters; - } - - /** - * Update Resource value after change RezAttrTelemetry in config Profile - * sent response Read to Client and add path to pathResAttrTelemetry in LwM2MClient.getAttrTelemetryObserveValue() - * - * @param lwServer - LeshanServer - * @param registration - Registration LwM2M Client - * @param targets - path Resources == [ "/2/0/0", "/2/0/1"] - */ - private void updateResourceValueObserve(LeshanServer lwServer, Registration registration, Set targets, String typeOper) { - targets.forEach(target -> { - LwM2mPath pathIds = new LwM2mPath(target); - if (pathIds.isResource()) { - if (GET_TYPE_OPER_READ.equals(typeOper)) { - lwM2MTransportRequest.sendAllRequest(lwServer, registration, target, typeOper, - ContentFormat.TLV.getName(), null, null, null, this.context.getCtxServer().getTimeout(), - false); - } else if (GET_TYPE_OPER_OBSERVE.equals(typeOper)) { - lwM2MTransportRequest.sendAllRequest(lwServer, registration, target, typeOper, - null, null, null, null, this.context.getCtxServer().getTimeout(), - false); - } - } - }); - } - - private void cancelObserveIsValue(LeshanServer lwServer, Registration registration, Set paramAnallyzer) { - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClientWithReg(registration, null); - paramAnallyzer.forEach(p -> { - if (this.getResourceValue(lwM2MClient, new LwM2mPath(p)) != null) { - this.setCancelObservationRecourse(lwServer, registration, p); - } - } - ); - } - - private ResourceValue getResourceValue(LwM2MClient lwM2MClient, LwM2mPath pathIds) { - ResourceValue resourceValue = null; - if (pathIds.isResource()) { - resourceValue = lwM2MClient.getResources().get(pathIds.toString()); - } - return resourceValue; - } - - /** - * Trigger Server path = "/1/0/8" - * - * Trigger bootStrap path = "/1/0/9" - have to implemented on client - */ - public void doTrigger(LeshanServer lwServer, Registration registration, String path) { - lwM2MTransportRequest.sendAllRequest(lwServer, registration, path, POST_TYPE_OPER_EXECUTE, - ContentFormat.TLV.getName(), null, null, null, this.context.getCtxServer().getTimeout(), - false); - } - - /** - * Session device in thingsboard is closed - * - * @param sessionInfo - lwm2m client - */ - private void doCloseSession(SessionInfoProto sessionInfo) { - TransportProtos.SessionEvent event = SessionEvent.CLOSED; - TransportProtos.SessionEventMsg msg = TransportProtos.SessionEventMsg.newBuilder() - .setSessionType(TransportProtos.SessionType.ASYNC) - .setEvent(event).build(); - transportService.process(sessionInfo, msg, null); - } - - /** - * Deregister session in transport - * - * @param sessionInfo - lwm2m client - */ - private void doDisconnect(SessionInfoProto sessionInfo) { - transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.CLOSED), null); - transportService.deregisterSession(sessionInfo); - } - - private void checkInactivityAndReportActivity() { - lwM2mInMemorySecurityStore.getSessions().forEach((key, value) -> this.checkInactivity(this.getValidateSessionInfo(key))); - } - - /** - * if sessionInfo removed from sessions, then new registerAsyncSession - * @param sessionInfo - - */ - private void checkInactivity(SessionInfoProto sessionInfo) { - if (transportService.reportActivity(sessionInfo) == null) { - transportService.registerAsyncSession(sessionInfo, new LwM2MSessionMsgListener(this, sessionInfo)); - } - } - - public void sentLogsToThingsboard(String msg, Registration registration) { - if (msg != null) { - JsonObject telemetries = new JsonObject(); - telemetries.addProperty(LOG_LW2M_TELEMETRY, msg); - this.updateParametersOnThingsboard(telemetries, LwM2MTransportHandler.DEVICE_TELEMETRY_TOPIC, registration); - } - } - - /** - * @param path - path resource - * @return - value of Resource or null - */ - public String getResourceValueToString(LwM2MClient lwM2MClient, String path) { - LwM2mPath pathIds = new LwM2mPath(path); - ResourceValue resourceValue = this.getResourceValue(lwM2MClient, pathIds); - return (resourceValue == null) ? null : - (String) this.converter.convertValue(resourceValue.getResourceValue(), this.context.getCtxServer().getResourceModelType(lwM2MClient.getRegistration(), pathIds), ResourceModel.Type.STRING, pathIds); - } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServiceImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServiceImpl.java new file mode 100644 index 0000000000..2a6af4e19e --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServiceImpl.java @@ -0,0 +1,1132 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.server; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.model.ResourceModel; +import org.eclipse.leshan.core.node.LwM2mMultipleResource; +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.observation.Observation; +import org.eclipse.leshan.core.request.ContentFormat; +import org.eclipse.leshan.core.request.WriteRequest; +import org.eclipse.leshan.core.response.ReadResponse; +import org.eclipse.leshan.core.util.NamedThreadFactory; +import org.eclipse.leshan.server.californium.LeshanServer; +import org.eclipse.leshan.server.registration.Registration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.data.DeviceProfile; +import org.thingsboard.server.common.transport.TransportService; +import org.thingsboard.server.common.transport.adaptor.AdaptorException; +import org.thingsboard.server.common.transport.adaptor.JsonConverter; +import org.thingsboard.server.common.transport.service.DefaultTransportService; +import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.gen.transport.TransportProtos.SessionEvent; +import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; +import org.thingsboard.server.gen.transport.TransportProtos.ToTransportUpdateCredentialsProto; +import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; +import org.thingsboard.server.transport.lwm2m.server.client.AttrTelemetryObserveValue; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue; +import org.thingsboard.server.transport.lwm2m.server.client.ResultsAnalyzerParameters; +import org.thingsboard.server.transport.lwm2m.server.secure.LwM2mInMemorySecurityStore; +import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; + +import javax.annotation.PostConstruct; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Random; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.stream.Collectors; + +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.DEFAULT_TIMEOUT; +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_OBSERVE; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.GET_TYPE_OPER_READ; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.LOG_LW2M_ERROR; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.LOG_LW2M_INFO; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.LOG_LW2M_TELEMETRY; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.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.SERVICE_CHANNEL; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.getAckCallback; + +@Slf4j +@Service("LwM2MTransportService") +@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' ) || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") +public class LwM2MTransportServiceImpl implements LwM2MTransportService { + + private ExecutorService executorRegistered; + private ExecutorService executorUpdateRegistered; + private ExecutorService executorUnRegistered; + private LwM2mValueConverterImpl converter; + protected final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); + protected final Lock writeLock = readWriteLock.writeLock(); + + + @Autowired + private TransportService transportService; + + @Autowired + public LwM2MTransportContextServer context; + + @Autowired + private LwM2MTransportRequest lwM2MTransportRequest; + + @Autowired + LwM2mInMemorySecurityStore lwM2mInMemorySecurityStore; + + @PostConstruct + public void init() { + this.context.getScheduler().scheduleAtFixedRate(this::checkInactivityAndReportActivity, new Random().nextInt((int) context.getCtxServer().getSessionReportTimeout()), context.getCtxServer().getSessionReportTimeout(), TimeUnit.MILLISECONDS); + this.executorRegistered = Executors.newCachedThreadPool( + new NamedThreadFactory(String.format("LwM2M %s channel registered", SERVICE_CHANNEL))); + this.executorUpdateRegistered = Executors.newCachedThreadPool( + new NamedThreadFactory(String.format("LwM2M %s channel update registered", SERVICE_CHANNEL))); + this.executorUnRegistered = Executors.newCachedThreadPool( + new NamedThreadFactory(String.format("LwM2M %s channel un registered", SERVICE_CHANNEL))); + this.converter = LwM2mValueConverterImpl.getInstance(); + } + + /** + * Start registration device + * Create session: Map, LwM2MClient> + * 1. replaceNewRegistration -> (solving the problem of incorrect termination of the previous session with this endpoint) + * 1.1 When we initialize the registration, we register the session by endpoint. + * 1.2 If the server has incomplete requests (canceling the registration of the previous session), + * delete the previous session only by the previous registration.getId + * 1.2 Add Model (Entity) for client (from registration & observe) by registration.getId + * 1.2 Remove from sessions Model by enpPoint + * Next -> Create new LwM2MClient for current session -> setModelClient... + * + * @param lwServer - LeshanServer + * @param registration - Registration LwM2M Client + * @param previousObsersations - may be null + */ + public void onRegistered(LeshanServer lwServer, Registration registration, Collection previousObsersations) { + executorRegistered.submit(() -> { + try { + log.info("[{}] [{{}] Client: create after Registration", registration.getEndpoint(), registration.getId()); + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.updateInSessionsLwM2MClient(lwServer, registration); + if (lwM2MClient != null) { + lwM2MClient.setLwM2MTransportServiceImpl(this); + lwM2MClient.setSessionUuid(UUID.randomUUID()); + this.sentLogsToThingsboard(LOG_LW2M_INFO + ": Client Registered", registration); + this.setLwM2MClient(lwServer, registration, lwM2MClient); + SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration); + if (sessionInfo != null) { + lwM2MClient.setDeviceUuid(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB())); + lwM2MClient.setProfileUuid(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); + lwM2MClient.setDeviceName(sessionInfo.getDeviceName()); + lwM2MClient.setDeviceProfileName(sessionInfo.getDeviceType()); + transportService.registerAsyncSession(sessionInfo, new LwM2MSessionMsgListener(this, sessionInfo)); + transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN), null); + transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), null); + this.sentLogsToThingsboard(LOG_LW2M_INFO + ": Client create after Registration", registration); + } else { + log.error("Client: [{}] onRegistered [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); + } + } else { + log.error("Client: [{}] onRegistered [{}] name [{}] lwM2MClient ", registration.getId(), registration.getEndpoint(), null); + } + } catch (Throwable t) { + log.error("[{}] endpoint [{}] error Unable registration.", registration.getEndpoint(), t); + } + }); + } + + /** + * if sessionInfo removed from sessions, then new registerAsyncSession + * @param lwServer - LeshanServer + * @param registration - Registration LwM2M Client + */ + public void updatedReg(LeshanServer lwServer, Registration registration) { + executorUpdateRegistered.submit(() -> { + try { + SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration); + if (sessionInfo != null) { + this.checkInactivity(sessionInfo); + log.info("Client: [{}] updatedReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType()); + } else { + log.error("Client: [{}] updatedReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); + } + } catch (Throwable t) { + log.error("[{}] endpoint [{}] error Unable update registration.", registration.getEndpoint(), t); + } + }); + } + + + /** + * @param registration - Registration LwM2M Client + * @param observations - All paths observations before unReg + * !!! Warn: if have not finishing unReg, then this operation will be finished on next Client`s connect + */ + public void unReg(Registration registration, Collection observations) { + executorUnRegistered.submit(() -> { + try { + this.sentLogsToThingsboard(LOG_LW2M_INFO + ": Client unRegistration", registration); + this.closeClientSession(registration); + } catch (Throwable t) { + log.error("[{}] endpoint [{}] error Unable un registration.", registration.getEndpoint(), t); + } + }); + } + + private void closeClientSession(Registration registration) { + SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration); + if (sessionInfo != null) { + transportService.deregisterSession(sessionInfo); + this.doCloseSession(sessionInfo); + lwM2mInMemorySecurityStore.delRemoveSessionAndListener(registration.getId()); + if (lwM2mInMemorySecurityStore.getProfiles().size() > 0) { + this.syncSessionsAndProfiles(); + } + log.info("Client close session: [{}] unReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType()); + } else { + log.error("Client close session: [{}] unReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); + } + } + + public void onSleepingDev(Registration registration) { + log.info("[{}] [{}] Received endpoint Sleeping version event", registration.getId(), registration.getEndpoint()); + //TODO: associate endpointId with device information. + } + + /** + * Those methods are called by the protocol stage thread pool, this means that execution MUST be done in a short delay, + * * if you need to do long time processing use a dedicated thread pool. + * + * @param registration - + */ + protected void onAwakeDev(Registration registration) { + log.info("[{}] [{}] Received endpoint Awake version event", registration.getId(), registration.getEndpoint()); + //TODO: associate endpointId with device information. + } + + /** + * This method is used to sync with sessions + * Removes a profile if not used in sessions + */ + private void syncSessionsAndProfiles() { + Map profilesClone = lwM2mInMemorySecurityStore.getProfiles().entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + profilesClone.forEach((k, v) -> { + String registrationId = lwM2mInMemorySecurityStore.getSessions().entrySet() + .stream() + .filter(e -> e.getValue().getProfileUuid().equals(k)) + .findFirst() + .map(Map.Entry::getKey) // return the key of the matching entry if found + .orElse(""); + if (registrationId.isEmpty()) { + lwM2mInMemorySecurityStore.getProfiles().remove(k); + } + }); + } + + /** + * #0 Add new ObjectModel to context + * Create new LwM2MClient for current session -> setModelClient... + * #1 Add all ObjectLinks (instance) to control the process of executing requests to the client + * to get the client model with current values + * #2 Get the client model with current values. Analyze the response in -> lwM2MTransportRequest.sendResponse + * + * @param lwServer - LeshanServer + * @param registration - Registration LwM2M Client + * @param lwM2MClient - object with All parameters off client + */ + private void setLwM2MClient(LeshanServer lwServer, Registration registration, LwM2MClient lwM2MClient) { + Arrays.stream(registration.getObjectLinks()).forEach(url -> { + LwM2mPath pathIds = new LwM2mPath(url.getUrl()); + if (pathIds.isObjectInstance() && !pathIds.isResource()) { + lwM2MClient.getPendingRequests().add(url.getUrl()); + } + }); + // #2 + Arrays.stream(registration.getObjectLinks()).forEach(url -> { + LwM2mPath pathIds = new LwM2mPath(url.getUrl()); + if (pathIds.isObjectInstance() && !pathIds.isResource()) { + lwM2MTransportRequest.sendAllRequest(lwServer, registration, url.getUrl(), GET_TYPE_OPER_READ, ContentFormat.TLV.getName(), + lwM2MClient, null, null, this.context.getCtxServer().getTimeout(), false); + } + }); + } + + /** + * @param registration - Registration LwM2M Client + * @return - sessionInfo after access connect client + */ + private SessionInfoProto getValidateSessionInfo(Registration registration) { + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClientWithReg(registration, null); + return getNewSessionInfoProto(lwM2MClient); + + } + + /** + * + * @param registrationId - + * @return - + */ + private SessionInfoProto getValidateSessionInfo(String registrationId) { + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClientWithReg(null, registrationId); + return getNewSessionInfoProto(lwM2MClient); + } + + private SessionInfoProto getNewSessionInfoProto(LwM2MClient lwM2MClient) { + if (lwM2MClient != null) { + ValidateDeviceCredentialsResponseMsg msg = lwM2MClient.getCredentialsResponse(); + if (msg == null || msg.getDeviceInfo() == null) { + log.error("[{}] [{}]", lwM2MClient.getEndPoint(), CLIENT_NOT_AUTHORIZED); + this.closeClientSession(lwM2MClient.getRegistration()); + return null; + } else { + return SessionInfoProto.newBuilder() + .setNodeId(this.context.getNodeId()) + .setSessionIdMSB(lwM2MClient.getSessionUuid().getMostSignificantBits()) + .setSessionIdLSB(lwM2MClient.getSessionUuid().getLeastSignificantBits()) + .setDeviceIdMSB(msg.getDeviceInfo().getDeviceIdMSB()) + .setDeviceIdLSB(msg.getDeviceInfo().getDeviceIdLSB()) + .setTenantIdMSB(msg.getDeviceInfo().getTenantIdMSB()) + .setTenantIdLSB(msg.getDeviceInfo().getTenantIdLSB()) + .setDeviceName(msg.getDeviceInfo().getDeviceName()) + .setDeviceType(msg.getDeviceInfo().getDeviceType()) + .setDeviceProfileIdLSB(msg.getDeviceInfo().getDeviceProfileIdLSB()) + .setDeviceProfileIdMSB(msg.getDeviceInfo().getDeviceProfileIdMSB()) + .build(); + } + } + return null; + } + + /** + * Add attribute/telemetry information from Client and credentials/Profile to client model and start observe + * !!! if the resource has an observation, but no telemetry or attribute - the observation will not use + * #1 Sending Attribute Telemetry with value to thingsboard only once at the start of the connection + * #2 Start observe + * + * @param lwM2MClient - LwM2M Client + */ + + public void updatesAndSentModelParameter(LwM2MClient lwM2MClient) { + // #1 + this.updateAttrTelemetry(lwM2MClient.getRegistration(), true, null); + // #2 + this.onSentObserveToClient(lwM2MClient.getLwServer(), lwM2MClient.getRegistration()); + + } + + /** + * If there is a difference in values between the current resource values and the shared attribute values + * when the client connects to the server + * #1 get attributes name from profile include name resources in ModelObject if resource isWritable + * #2.1 #1 size > 0 => send Request getAttributes to thingsboard + * #2.2 #1 size == 0 => continue normal process + * + * @param lwM2MClient - LwM2M Client + */ + public void putDelayedUpdateResourcesThingsboard(LwM2MClient lwM2MClient) { + SessionInfoProto sessionInfo = this.getValidateSessionInfo(lwM2MClient.getRegistration()); + if (sessionInfo != null) { + //#1.1 + #1.2 + List attrSharedNames = this.getNamesAttrFromProfileIsWritable(lwM2MClient); + if (attrSharedNames.size() > 0) { + //#2.1 + try { + TransportProtos.GetAttributeRequestMsg getAttributeMsg = context.getAdaptor().convertToGetAttributes(null, attrSharedNames); + lwM2MClient.getDelayedRequestsId().add(getAttributeMsg.getRequestId()); + transportService.process(sessionInfo, getAttributeMsg, getAckCallback(lwM2MClient, getAttributeMsg.getRequestId(), DEVICE_ATTRIBUTES_REQUEST)); + } catch (AdaptorException e) { + log.warn("Failed to decode get attributes request", e); + } + } + // #2.2 + else { + lwM2MClient.onSuccessOrErrorDelayedRequests(null); + } + } + } + + /** + * Update resource value on client: if there is a difference in values between the current resource values and the shared attribute values + * #1 Get path resource by result attributesResponse + * #1.1 If two names have equal path => last time attribute + * #2.1 if there is a difference in values between the current resource values and the shared attribute values + * => sent to client Request Update of value (new value from shared attribute) + * and LwM2MClient.delayedRequests.add(path) + * #2.1 if there is not a difference in values between the current resource values and the shared attribute values + * + * @param attributesResponse - + * @param sessionInfo - + */ + public void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg attributesResponse, TransportProtos.SessionInfoProto sessionInfo) { + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(sessionInfo); + if (lwM2MClient.getDelayedRequestsId().contains(attributesResponse.getRequestId())) { + attributesResponse.getSharedAttributeListList().forEach(attr -> { + String path = this.getPathAttributeUpdate(sessionInfo, attr.getKv().getKey()); + // #1.1 + if (lwM2MClient.getDelayedRequests().containsKey(path) && attr.getTs() > lwM2MClient.getDelayedRequests().get(path).getTs()) { + lwM2MClient.getDelayedRequests().put(path, attr); + } else { + lwM2MClient.getDelayedRequests().put(path, attr); + } + }); + // #2.1 + lwM2MClient.getDelayedRequests().forEach((k, v) -> { + ArrayList listV = new ArrayList<>(); + listV.add(v.getKv()); + this.putDelayedUpdateResourcesClient(lwM2MClient, this.getResourceValueToString(lwM2MClient, k), getJsonObject(listV).get(v.getKv().getKey()), k); + }); + lwM2MClient.getDelayedRequestsId().remove(attributesResponse.getRequestId()); + if (lwM2MClient.getDelayedRequests().size() == 0) { + lwM2MClient.onSuccessOrErrorDelayedRequests(null); + } + } + } + + private void putDelayedUpdateResourcesClient(LwM2MClient lwM2MClient, Object valueOld, Object valueNew, String path) { + if (valueNew != null && !valueNew.toString().equals(valueOld.toString())) { + lwM2MTransportRequest.sendAllRequest(lwM2MClient.getLwServer(), lwM2MClient.getRegistration(), path, POST_TYPE_OPER_WRITE_REPLACE, + ContentFormat.TLV.getName(), lwM2MClient, null, valueNew, this.context.getCtxServer().getTimeout(), + true); + } + } + + /** + * Get names and keyNames from profile shared!!!! attr resources IsWritable + * @param lwM2MClient - + * @return ArrayList keyNames from profile attr resources shared!!!! && IsWritable + */ + private List getNamesAttrFromProfileIsWritable(LwM2MClient lwM2MClient) { + AttrTelemetryObserveValue profile = lwM2mInMemorySecurityStore.getProfile(lwM2MClient.getProfileUuid()); + Set attrSet = new Gson().fromJson(profile.getPostAttributeProfile(), Set.class); + ConcurrentMap keyNamesMap = new Gson().fromJson(profile.getPostKeyNameProfile().toString(), ConcurrentHashMap.class); + + ConcurrentMap keyNamesIsWritable = keyNamesMap.entrySet() + .stream() + .filter(e -> (attrSet.contains(e.getKey()) && context.getCtxServer().getResourceModel(lwM2MClient.getRegistration(), new LwM2mPath(e.getKey())) != null && + context.getCtxServer().getResourceModel(lwM2MClient.getRegistration(), new LwM2mPath(e.getKey())).operations.isWritable())) + .collect(Collectors.toConcurrentMap(Map.Entry::getKey, Map.Entry::getValue)); + + Set namesIsWritable = ConcurrentHashMap.newKeySet(); + namesIsWritable.addAll(new HashSet<>(keyNamesIsWritable.values())); + return new ArrayList<>(namesIsWritable); + } + + + /** + * Sent Attribute and Telemetry to Thingsboard + * #1 - get AttrName/TelemetryName with value: + * #1.1 from Client + * #1.2 from LwM2MClient: + * -- resourceId == path from AttrTelemetryObserveValue.postAttributeProfile/postTelemetryProfile/postObserveProfile + * -- AttrName/TelemetryName == resourceName from ModelObject.objectModel, value from ModelObject.instance.resource(resourceId) + * #2 - set Attribute/Telemetry + * + * @param registration - Registration LwM2M Client + */ + private void updateAttrTelemetry(Registration registration, boolean start, Set paths) { + JsonObject attributes = new JsonObject(); + JsonObject telemetries = new JsonObject(); + if (start) { + // #1.1 + JsonObject attributeClient = this.getAttributeClient(registration); + if (attributeClient != null) { + attributeClient.entrySet().forEach(p -> attributes.add(p.getKey(), p.getValue())); + } + } + // #1.2 + CountDownLatch cancelLatch = new CountDownLatch(1); + this.getParametersFromProfile(attributes, telemetries, registration, paths); + cancelLatch.countDown(); + try { + cancelLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + log.error("[{}] updateAttrTelemetry", e.toString()); + } + if (attributes.getAsJsonObject().entrySet().size() > 0) + this.updateParametersOnThingsboard(attributes, DEVICE_ATTRIBUTES_TOPIC, registration); + if (telemetries.getAsJsonObject().entrySet().size() > 0) + this.updateParametersOnThingsboard(telemetries, DEVICE_TELEMETRY_TOPIC, registration); + } + + /** + * get AttrName/TelemetryName with value from Client + * + * @param registration - + * @return - JsonObject, format: {name: value}} + */ + private JsonObject getAttributeClient(Registration registration) { + if (registration.getAdditionalRegistrationAttributes().size() > 0) { + JsonObject resNameValues = new JsonObject(); + registration.getAdditionalRegistrationAttributes().forEach(resNameValues::addProperty); + return resNameValues; + } + return null; + } + + /** + * @param attributes - new JsonObject + * @param telemetry - new JsonObject + * @param registration - Registration LwM2M Client + * result: add to JsonObject those resources to which the user is subscribed and they have a value + * if path==null add All resources else only one + * (attributes/telemetry): new {name(Attr/Telemetry):value} + */ + private void getParametersFromProfile(JsonObject attributes, JsonObject telemetry, Registration registration, Set path) { + AttrTelemetryObserveValue attrTelemetryObserveValue = lwM2mInMemorySecurityStore.getProfiles().get(lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getProfileUuid()); + attrTelemetryObserveValue.getPostAttributeProfile().forEach(p -> { + LwM2mPath pathIds = new LwM2mPath(p.getAsString().toString()); + if (pathIds.isResource()) { + if (path == null || path.contains(p.getAsString())) { + this.addParameters(p.getAsString().toString(), attributes, registration); + } + } + }); + attrTelemetryObserveValue.getPostTelemetryProfile().forEach(p -> { + LwM2mPath pathIds = new LwM2mPath(p.getAsString().toString()); + if (pathIds.isResource()) { + if (path == null || path.contains(p.getAsString())) { + this.addParameters(p.getAsString().toString(), telemetry, registration); + } + } + }); + } + + /** + * @param parameters - JsonObject attributes/telemetry + * @param registration - Registration LwM2M Client + */ + private void addParameters(String path, JsonObject parameters, Registration registration) { + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getSessions().get(registration.getId()); + JsonObject names = lwM2mInMemorySecurityStore.getProfiles().get(lwM2MClient.getProfileUuid()).getPostKeyNameProfile(); + String resName = String.valueOf(names.get(path)); + if (resName != null && !resName.isEmpty()) { + try { + String resValue = this.getResourceValueToString(lwM2MClient, path); + if (resValue != null) { + parameters.addProperty(resName, resValue); + } + } catch (Exception e) { + log.error(e.getStackTrace().toString()); + } + } + } + + /** + * Prepare Sent to Thigsboard callback - Attribute or Telemetry + * + * @param msg - JsonArray: [{name: value}] + * @param topicName - Api Attribute or Telemetry + * @param registration - Id of Registration LwM2M Client + */ + public void updateParametersOnThingsboard(JsonElement msg, String topicName, Registration registration) { + SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration); + if (sessionInfo != null) { + context.sentParametersOnThingsboard(msg, topicName, sessionInfo); + } else { + log.error("Client: [{}] updateParametersOnThingsboard [{}] sessionInfo ", registration, null); + } + } + + /** + * Start observe + * #1 - Analyze: + * #1.1 path in observe == (attribute or telemetry) + * #2 Analyze after sent request (response): + * #2.1 First: lwM2MTransportRequest.sendResponse -> ObservationListener.newObservation + * #2.2 Next: ObservationListener.onResponse * + * + * @param lwServer - LeshanServer + * @param registration - Registration LwM2M Client + */ + private void onSentObserveToClient(LeshanServer lwServer, Registration registration) { + if (lwServer.getObservationService().getObservations(registration).size() > 0) { + this.setCancelObservations(lwServer, registration); + } + UUID profileUUid = lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getProfileUuid(); + AttrTelemetryObserveValue attrTelemetryObserveValue = lwM2mInMemorySecurityStore.getProfiles().get(profileUUid); + attrTelemetryObserveValue.getPostObserveProfile().forEach(p -> { + // #1.1 + String target = (getValidateObserve(attrTelemetryObserveValue.getPostAttributeProfile(), p.getAsString().toString())) ? + p.getAsString().toString() : (getValidateObserve(attrTelemetryObserveValue.getPostTelemetryProfile(), p.getAsString().toString())) ? + p.getAsString().toString() : null; + if (target != null) { + // #2 + if (this.getResourceValueToString(lwM2mInMemorySecurityStore.getSessions().get(registration.getId()), target) != null) { + lwM2MTransportRequest.sendAllRequest(lwServer, registration, target, GET_TYPE_OPER_OBSERVE, + null, null, null, null, this.context.getCtxServer().getTimeout(), + false); + } + } + }); + } + + public void setCancelObservations(LeshanServer lwServer, Registration registration) { + if (registration != null) { + Set observations = lwServer.getObservationService().getObservations(registration); + observations.forEach(observation -> this.setCancelObservationRecourse(lwServer, registration, observation.getPath().toString())); + } + } + + /** + * lwM2MTransportRequest.sendAllRequest(lwServer, registration, path, POST_TYPE_OPER_OBSERVE_CANCEL, null, null, null, null, context.getTimeout()); + * At server side this will not remove the observation from the observation store, to do it you need to use + * {@code ObservationService#cancelObservation()} + */ + public void setCancelObservationRecourse(LeshanServer lwServer, Registration registration, String path) { + CountDownLatch cancelLatch = new CountDownLatch(1); + lwServer.getObservationService().cancelObservations(registration, path); + cancelLatch.countDown(); + try { + cancelLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + log.error("", e); + } + } + + /** + * @param parameters - JsonArray postAttributeProfile/postTelemetryProfile + * @param path - recourse from postObserveProfile + * @return rez - true if path observe is in attribute/telemetry + */ + private boolean getValidateObserve(JsonElement parameters, String path) { + AtomicBoolean rez = new AtomicBoolean(false); + if (parameters.isJsonArray()) { + parameters.getAsJsonArray().forEach(p -> { + if (p.getAsString().toString().equals(path)) rez.set(true); + } + ); + } else if (parameters.isJsonObject()) { + rez.set((parameters.getAsJsonObject().entrySet()).stream().map(json -> json.toString()) + .filter(path::equals).findAny().orElse(null) != null); + } + return rez.get(); + } + + /** + * Sending observe value to thingsboard from ObservationListener.onResponse: object, instance, SingleResource or MultipleResource + * + * @param registration - Registration LwM2M Client + * @param path - observe + * @param response - observe + */ + + public void onObservationResponse(Registration registration, String path, ReadResponse response) { + if (response.getContent() != null) { + if (response.getContent() instanceof LwM2mObject) { +// LwM2mObject content = (LwM2mObject) response.getContent(); + } else if (response.getContent() instanceof LwM2mObjectInstance) { +// LwM2mObjectInstance content = (LwM2mObjectInstance) response.getContent(); + } else if (response.getContent() instanceof LwM2mSingleResource) { + LwM2mSingleResource content = (LwM2mSingleResource) response.getContent(); + this.onObservationSetResourcesValue(registration, content.getValue(), null, path); + } else if (response.getContent() instanceof LwM2mMultipleResource) { + LwM2mMultipleResource content = (LwM2mMultipleResource) response.getContent(); + this.onObservationSetResourcesValue(registration, null, content.getValues(), path); + } + } + } + + /** + * Sending observe value of resources to thingsboard + * #1 Return old Value Resource from LwM2MClient + * #2 Update new Resources (replace old Resource Value on new Resource Value) + * + * @param registration - Registration LwM2M Client + * @param value - LwM2mSingleResource response.getContent() + * @param values - LwM2mSingleResource response.getContent() + * @param path - resource + */ + private void onObservationSetResourcesValue(Registration registration, Object value, Map values, String path) { + boolean isChange = false; + try { + writeLock.lock(); + try { + // #1 + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClientWithReg(registration, null); + LwM2mPath pathIds = new LwM2mPath(path); + log.warn("#0 nameDevice: [{}] resultIds: [{}] value: [{}], values: [{}] ", lwM2MClient.getDeviceName(), pathIds, value, values); + ResourceModel.Type resModelType = context.getCtxServer().getResourceModelType(registration, pathIds); + ResourceValue resValueOld = lwM2MClient.getResources().get(path); + // #2 + if (resValueOld.isMultiInstances() && !values.toString().equals(resValueOld.getResourceValue().toString())) { + ResourceValue resourceValue = new ResourceValue(values, null, true); + lwM2MClient.getResources().put(path, resourceValue); + isChange = true; + } else if (!LwM2MTransportHandler.equalsResourceValue(resValueOld.getValue(), value, resModelType, pathIds)) { + ResourceValue resourceValue = new ResourceValue(null, value, false); + lwM2MClient.getResources().put(path, resourceValue); + isChange = true; + } + } finally { + writeLock.unlock(); + } + } + catch (Exception e) { + log.error("#1_1 Update ResourcesValue after Observation in CountDownLatch is unsuccessfully path: [{}] value: [{}] [{}]", path, value, e.toString()); + } + if (isChange) { + Set paths = new HashSet<>(); + paths.add(path); + this.updateAttrTelemetry(registration, false, paths); + } + } + + /** + * @param updateCredentials - Credentials include config only security Client (without config attr/telemetry...) + * config attr/telemetry... in profile + */ + public void onToTransportUpdateCredentials(ToTransportUpdateCredentialsProto updateCredentials) { + log.info("[{}] idList [{}] valueList updateCredentials", updateCredentials.getCredentialsIdList(), updateCredentials.getCredentialsValueList()); + } + + /** + * Update - sent request in change value resources in Client + * Path to resources from profile equal keyName or from ModelObject equal name + * Only for resources: isWritable && isPresent as attribute in profile -> AttrTelemetryObserveValue (format: CamelCase) + * Delete - nothing * + * + * @param msg - + */ + public void onAttributeUpdate(TransportProtos.AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo) { + if (msg.getSharedUpdatedCount() > 0) { + JsonElement el = JsonConverter.toJson(msg); + el.getAsJsonObject().entrySet().forEach(de -> { + String path = this.getPathAttributeUpdate(sessionInfo, de.getKey()); + String value = de.getValue().getAsString(); + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getSession(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())).entrySet().iterator().next().getValue(); + AttrTelemetryObserveValue profile = lwM2mInMemorySecurityStore.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); + ResourceModel resourceModel = context.getCtxServer().getResourceModel(lwM2MClient.getRegistration(), new LwM2mPath(path)); + if (!path.isEmpty() && (this.validatePathInAttrProfile(profile, path) || this.validatePathInTelemetryProfile(profile, path))) { + if (resourceModel != null && resourceModel.operations.isWritable()) { + lwM2MTransportRequest.sendAllRequest(lwM2MClient.getLwServer(), lwM2MClient.getRegistration(), path, POST_TYPE_OPER_WRITE_REPLACE, + ContentFormat.TLV.getName(), lwM2MClient, null, value, this.context.getCtxServer().getTimeout(), + false); + } else { + log.error("Resource path - [{}] value - [{}] is not Writable and cannot be updated", path, value); + String logMsg = String.format(LOG_LW2M_ERROR + ": attributeUpdate: Resource path - %s value - %s is not Writable and cannot be updated", path, value); + this.sentLogsToThingsboard(logMsg, lwM2MClient.getRegistration()); + } + } else { + log.error("Attribute name - [{}] value - [{}] is not present as attribute in profile and cannot be updated", de.getKey(), value); + String logMsg = String.format(LOG_LW2M_ERROR + ": attributeUpdate: attribute name - %s value - %s is not present as attribute in profile and cannot be updated", de.getKey(), value); + this.sentLogsToThingsboard(logMsg, lwM2MClient.getRegistration()); + } + }); + } else if (msg.getSharedDeletedCount() > 0) { + log.info("[{}] delete [{}] onAttributeUpdate", msg.getSharedDeletedList(), sessionInfo); + } + } + + /** + * Get path to resource from profile equal keyName or from ModelObject equal name + * Only for resource: isWritable && isPresent as attribute in profile -> AttrTelemetryObserveValue (format: CamelCase) + * + * @param sessionInfo - + * @param name - + * @return path if path isPresent in postProfile + */ + private String getPathAttributeUpdate(TransportProtos.SessionInfoProto sessionInfo, String name) { + String profilePath = this.getPathAttributeUpdateProfile(sessionInfo, name); +// return !profilePath.isEmpty() ? profilePath : this.getPathAttributeUpdateModelObject(name); + return !profilePath.isEmpty() ? profilePath : null; + } + + /** + * @param profile - + * @param path - + * @return true if path isPresent in postAttributeProfile + */ + private boolean validatePathInAttrProfile(AttrTelemetryObserveValue profile, String path) { + Set attributesSet = new Gson().fromJson(profile.getPostAttributeProfile(), Set.class); + return attributesSet.stream().filter(p -> p.equals(path)).findFirst().isPresent(); + } + + /** + * @param profile - + * @param path - + * @return true if path isPresent in postAttributeProfile + */ + private boolean validatePathInTelemetryProfile(AttrTelemetryObserveValue profile, String path) { + Set telemetriesSet = new Gson().fromJson(profile.getPostTelemetryProfile(), Set.class); + return telemetriesSet.stream().filter(p -> p.equals(path)).findFirst().isPresent(); + } + + + /** + * Get path to resource from profile equal keyName + * + * @param sessionInfo - + * @param name - + * @return - + */ + private String getPathAttributeUpdateProfile(TransportProtos.SessionInfoProto sessionInfo, String name) { + AttrTelemetryObserveValue profile = lwM2mInMemorySecurityStore.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); + return profile.getPostKeyNameProfile().getAsJsonObject().entrySet().stream() + .filter(e -> e.getValue().getAsString().equals(name)).findFirst().map(Map.Entry::getKey) + .orElse(""); + } + + /** + * Update resource (attribute) value on thingsboard after update value in client + * + * @param registration - + * @param path - + * @param request - + */ + public void onAttributeUpdateOk(Registration registration, String path, WriteRequest request, boolean isDelayedUpdate) { + ResourceModel resource = context.getCtxServer().getResourceModel(registration, new LwM2mPath(path)); + if (resource.multiple) { + this.onObservationSetResourcesValue(registration, null, ((LwM2mSingleResource) request.getNode()).getValues(), path); + } else { + this.onObservationSetResourcesValue(registration, ((LwM2mSingleResource) request.getNode()).getValue(), null, path); + } + if (isDelayedUpdate) lwM2mInMemorySecurityStore.getLwM2MClientWithReg(registration, null) + .onSuccessOrErrorDelayedRequests(request.getPath().toString()); + } + + /** + * @param sessionInfo - + * @param deviceProfile - + */ + public void onDeviceProfileUpdate(TransportProtos.SessionInfoProto sessionInfo, DeviceProfile deviceProfile) { + Set registrationIds = lwM2mInMemorySecurityStore.getSessions().entrySet() + .stream() + .filter(e -> e.getValue().getProfileUuid().equals(deviceProfile.getUuidId())) + .map(Map.Entry::getKey).sorted().collect(Collectors.toCollection(LinkedHashSet::new)); + if (registrationIds.size() > 0) { + this.onDeviceUpdateChangeProfile(registrationIds, deviceProfile); + } + } + + /** + * @param sessionInfo - + * @param device - + * @param deviceProfileOpt - + */ + public void onDeviceUpdate(TransportProtos.SessionInfoProto sessionInfo, Device device, Optional deviceProfileOpt) { + Optional registrationIdOpt = lwM2mInMemorySecurityStore.getSessions().entrySet().stream() + .filter(e -> device.getUuidId().equals(e.getValue().getDeviceUuid())) + .map(Map.Entry::getKey) + .findFirst(); + registrationIdOpt.ifPresent(registrationId -> this.onDeviceUpdateLwM2MClient(registrationId, device, deviceProfileOpt)); + } + + /** + * Update parameters device in LwM2MClient + * If new deviceProfile != old deviceProfile => update deviceProfile + * + * @param registrationId - + * @param device - + */ + private void onDeviceUpdateLwM2MClient(String registrationId, Device device, Optional deviceProfileOpt) { + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getSessions().get(registrationId); + lwM2MClient.setDeviceName(device.getName()); + if (!lwM2MClient.getProfileUuid().equals(device.getDeviceProfileId().getId())) { + Set registrationIds = new HashSet<>(); + registrationIds.add(registrationId); + deviceProfileOpt.ifPresent(deviceProfile -> this.onDeviceUpdateChangeProfile(registrationIds, deviceProfile)); + } + + lwM2MClient.setProfileUuid(device.getDeviceProfileId().getId()); + } + + /** + * #1 Read new, old Value (Attribute, Telemetry, Observe, KeyName) + * #2 Update in lwM2MClient: ...Profile if changes from update device + * #3 Equivalence test: old <> new Value (Attribute, Telemetry, Observe, KeyName) + * #3.1 Attribute isChange (add&del) + * #3.2 Telemetry isChange (add&del) + * #3.3 KeyName isChange (add) + * #4 update + * #4.1 add If #3 isChange, then analyze and update Value in Transport form Client and sent Value to thingsboard + * #4.2 del + * -- if add attributes includes del telemetry - result del for observe + * #5 + * #5.1 Observe isChange (add&del) + * #5.2 Observe.add + * -- path Attr/Telemetry includes newObserve and does not include oldObserve: sent Request observe to Client + * #5.3 Observe.del + * -- different between newObserve and oldObserve: sent Request cancel observe to client + * + * @param registrationIds - + * @param deviceProfile - + */ + private void onDeviceUpdateChangeProfile(Set registrationIds, DeviceProfile deviceProfile) { + + AttrTelemetryObserveValue attrTelemetryObserveValueOld = lwM2mInMemorySecurityStore.getProfiles().get(deviceProfile.getUuidId()); + if (lwM2mInMemorySecurityStore.addUpdateProfileParameters(deviceProfile)) { + + // #1 + JsonArray attributeOld = attrTelemetryObserveValueOld.getPostAttributeProfile(); + Set attributeSetOld = new Gson().fromJson(attributeOld, Set.class); + JsonArray telemetryOld = attrTelemetryObserveValueOld.getPostTelemetryProfile(); + Set telemetrySetOld = new Gson().fromJson(telemetryOld, Set.class); + JsonArray observeOld = attrTelemetryObserveValueOld.getPostObserveProfile(); + JsonObject keyNameOld = attrTelemetryObserveValueOld.getPostKeyNameProfile(); + + AttrTelemetryObserveValue attrTelemetryObserveValueNew = lwM2mInMemorySecurityStore.getProfiles().get(deviceProfile.getUuidId()); + JsonArray attributeNew = attrTelemetryObserveValueNew.getPostAttributeProfile(); + Set attributeSetNew = new Gson().fromJson(attributeNew, Set.class); + JsonArray telemetryNew = attrTelemetryObserveValueNew.getPostTelemetryProfile(); + Set telemetrySetNew = new Gson().fromJson(telemetryNew, Set.class); + JsonArray observeNew = attrTelemetryObserveValueNew.getPostObserveProfile(); + JsonObject keyNameNew = attrTelemetryObserveValueNew.getPostKeyNameProfile(); + + // #3 + ResultsAnalyzerParameters sentAttrToThingsboard = new ResultsAnalyzerParameters(); + // #3.1 + if (!attributeOld.equals(attributeNew)) { + ResultsAnalyzerParameters postAttributeAnalyzer = this.getAnalyzerParameters(new Gson().fromJson(attributeOld, Set.class), attributeSetNew); + sentAttrToThingsboard.getPathPostParametersAdd().addAll(postAttributeAnalyzer.getPathPostParametersAdd()); + sentAttrToThingsboard.getPathPostParametersDel().addAll(postAttributeAnalyzer.getPathPostParametersDel()); + } + // #3.2 + if (!attributeOld.equals(attributeNew)) { + ResultsAnalyzerParameters postTelemetryAnalyzer = this.getAnalyzerParameters(new Gson().fromJson(telemetryOld, Set.class), telemetrySetNew); + sentAttrToThingsboard.getPathPostParametersAdd().addAll(postTelemetryAnalyzer.getPathPostParametersAdd()); + sentAttrToThingsboard.getPathPostParametersDel().addAll(postTelemetryAnalyzer.getPathPostParametersDel()); + } + // #3.3 + if (!keyNameOld.equals(keyNameNew)) { + ResultsAnalyzerParameters keyNameChange = this.getAnalyzerKeyName(new Gson().fromJson(keyNameOld.toString(), ConcurrentHashMap.class), + new Gson().fromJson(keyNameNew.toString(), ConcurrentHashMap.class)); + sentAttrToThingsboard.getPathPostParametersAdd().addAll(keyNameChange.getPathPostParametersAdd()); + } + + // #4.1 add + if (sentAttrToThingsboard.getPathPostParametersAdd().size() > 0) { + // update value in Resources + registrationIds.forEach(registrationId -> { + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClientWithReg(null, registrationId); + LeshanServer lwServer = lwM2MClient.getLwServer(); + Registration registration = lwM2mInMemorySecurityStore.getByRegistration(registrationId); + log.warn("[{}] # 4.1", registration.getEndpoint()); + this.updateResourceValueObserve(lwServer, registration, sentAttrToThingsboard.getPathPostParametersAdd(), GET_TYPE_OPER_READ); + // sent attr/telemetry to tingsboard for new path + this.updateAttrTelemetry(registration, false, sentAttrToThingsboard.getPathPostParametersAdd()); + }); + } + // #4.2 del + if (sentAttrToThingsboard.getPathPostParametersDel().size() > 0) { + ResultsAnalyzerParameters sentAttrToThingsboardDel = this.getAnalyzerParameters(sentAttrToThingsboard.getPathPostParametersAdd(), sentAttrToThingsboard.getPathPostParametersDel()); + sentAttrToThingsboard.setPathPostParametersDel(sentAttrToThingsboardDel.getPathPostParametersDel()); + } + + // #5.1 + if (!observeOld.equals(observeNew)) { + Set observeSetOld = new Gson().fromJson(observeOld, Set.class); + Set observeSetNew = new Gson().fromJson(observeNew, Set.class); + //#5.2 add + // path Attr/Telemetry includes newObserve + attributeSetOld.addAll(telemetrySetOld); + ResultsAnalyzerParameters sentObserveToClientOld = this.getAnalyzerParametersIn(attributeSetOld, observeSetOld); // add observe + attributeSetNew.addAll(telemetrySetNew); + ResultsAnalyzerParameters sentObserveToClientNew = this.getAnalyzerParametersIn(attributeSetNew, observeSetNew); // add observe + // does not include oldObserve + ResultsAnalyzerParameters postObserveAnalyzer = this.getAnalyzerParameters(sentObserveToClientOld.getPathPostParametersAdd(), sentObserveToClientNew.getPathPostParametersAdd()); + // sent Request observe to Client + registrationIds.forEach(registrationId -> { + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(null, registrationId); + LeshanServer lwServer = lwM2MClient.getLwServer(); + Registration registration = lwM2mInMemorySecurityStore.getByRegistration(registrationId); + log.warn("[{}] # 5.1", registration.getEndpoint()); + this.updateResourceValueObserve(lwServer, registration, postObserveAnalyzer.getPathPostParametersAdd(), GET_TYPE_OPER_OBSERVE); + // 5.3 del + // sent Request cancel observe to Client + this.cancelObserveIsValue(lwServer, registration, postObserveAnalyzer.getPathPostParametersDel()); + }); + } + } + } + + /** + * Compare old list with new list after change AttrTelemetryObserve in config Profile + * + * @param parametersOld - + * @param parametersNew - + * @return ResultsAnalyzerParameters: add && new + */ + private ResultsAnalyzerParameters getAnalyzerParameters(Set parametersOld, Set parametersNew) { + ResultsAnalyzerParameters analyzerParameters = null; + if (!parametersOld.equals(parametersNew)) { + analyzerParameters = new ResultsAnalyzerParameters(); + analyzerParameters.setPathPostParametersAdd(parametersNew + .stream().filter(p -> !parametersOld.contains(p)).collect(Collectors.toSet())); + analyzerParameters.setPathPostParametersDel(parametersOld + .stream().filter(p -> !parametersNew.contains(p)).collect(Collectors.toSet())); + } + return analyzerParameters; + } + + private ResultsAnalyzerParameters getAnalyzerKeyName(ConcurrentMap keyNameOld, ConcurrentMap keyNameNew) { + ResultsAnalyzerParameters analyzerParameters = new ResultsAnalyzerParameters(); + Set paths = keyNameNew.entrySet() + .stream() + .filter(e -> !e.getValue().equals(keyNameOld.get(e.getKey()))) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)).keySet(); + analyzerParameters.setPathPostParametersAdd(paths); + return analyzerParameters; + } + + private ResultsAnalyzerParameters getAnalyzerParametersIn(Set parametersObserve, Set parameters) { + ResultsAnalyzerParameters analyzerParameters = new ResultsAnalyzerParameters(); + analyzerParameters.setPathPostParametersAdd(parametersObserve + .stream().filter(parameters::contains).collect(Collectors.toSet())); + return analyzerParameters; + } + + /** + * Update Resource value after change RezAttrTelemetry in config Profile + * sent response Read to Client and add path to pathResAttrTelemetry in LwM2MClient.getAttrTelemetryObserveValue() + * + * @param lwServer - LeshanServer + * @param registration - Registration LwM2M Client + * @param targets - path Resources == [ "/2/0/0", "/2/0/1"] + */ + private void updateResourceValueObserve(LeshanServer lwServer, Registration registration, Set targets, String typeOper) { + targets.forEach(target -> { + LwM2mPath pathIds = new LwM2mPath(target); + if (pathIds.isResource()) { + if (GET_TYPE_OPER_READ.equals(typeOper)) { + lwM2MTransportRequest.sendAllRequest(lwServer, registration, target, typeOper, + ContentFormat.TLV.getName(), null, null, null, this.context.getCtxServer().getTimeout(), + false); + } else if (GET_TYPE_OPER_OBSERVE.equals(typeOper)) { + lwM2MTransportRequest.sendAllRequest(lwServer, registration, target, typeOper, + null, null, null, null, this.context.getCtxServer().getTimeout(), + false); + } + } + }); + } + + private void cancelObserveIsValue(LeshanServer lwServer, Registration registration, Set paramAnallyzer) { + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClientWithReg(registration, null); + paramAnallyzer.forEach(p -> { + if (this.getResourceValue(lwM2MClient, new LwM2mPath(p)) != null) { + this.setCancelObservationRecourse(lwServer, registration, p); + } + } + ); + } + + private ResourceValue getResourceValue(LwM2MClient lwM2MClient, LwM2mPath pathIds) { + ResourceValue resourceValue = null; + if (pathIds.isResource()) { + resourceValue = lwM2MClient.getResources().get(pathIds.toString()); + } + return resourceValue; + } + + /** + * Trigger Server path = "/1/0/8" + * + * Trigger bootStrap path = "/1/0/9" - have to implemented on client + */ + public void doTrigger(LeshanServer lwServer, Registration registration, String path) { + lwM2MTransportRequest.sendAllRequest(lwServer, registration, path, POST_TYPE_OPER_EXECUTE, + ContentFormat.TLV.getName(), null, null, null, this.context.getCtxServer().getTimeout(), + false); + } + + /** + * Session device in thingsboard is closed + * + * @param sessionInfo - lwm2m client + */ + private void doCloseSession(SessionInfoProto sessionInfo) { + TransportProtos.SessionEvent event = SessionEvent.CLOSED; + TransportProtos.SessionEventMsg msg = TransportProtos.SessionEventMsg.newBuilder() + .setSessionType(TransportProtos.SessionType.ASYNC) + .setEvent(event).build(); + transportService.process(sessionInfo, msg, null); + } + + /** + * Deregister session in transport + * + * @param sessionInfo - lwm2m client + */ + public void doDisconnect(SessionInfoProto sessionInfo) { + transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.CLOSED), null); + transportService.deregisterSession(sessionInfo); + } + + private void checkInactivityAndReportActivity() { + lwM2mInMemorySecurityStore.getSessions().forEach((key, value) -> this.checkInactivity(this.getValidateSessionInfo(key))); + } + + /** + * if sessionInfo removed from sessions, then new registerAsyncSession + * @param sessionInfo - + */ + private void checkInactivity(SessionInfoProto sessionInfo) { + if (transportService.reportActivity(sessionInfo) == null) { + transportService.registerAsyncSession(sessionInfo, new LwM2MSessionMsgListener(this, sessionInfo)); + } + } + + public void sentLogsToThingsboard(String msg, Registration registration) { + if (msg != null) { + JsonObject telemetries = new JsonObject(); + telemetries.addProperty(LOG_LW2M_TELEMETRY, msg); + this.updateParametersOnThingsboard(telemetries, LwM2MTransportHandler.DEVICE_TELEMETRY_TOPIC, registration); + } + } + + /** + * @param path - path resource + * @return - value of Resource or null + */ + private String getResourceValueToString(LwM2MClient lwM2MClient, String path) { + LwM2mPath pathIds = new LwM2mPath(path); + ResourceValue resourceValue = this.getResourceValue(lwM2MClient, pathIds); + return (resourceValue == null) ? null : + (String) this.converter.convertValue(resourceValue.getResourceValue(), this.context.getCtxServer().getResourceModelType(lwM2MClient.getRegistration(), pathIds), ResourceModel.Type.STRING, pathIds); + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java index ea440a33d0..2028fb4f00 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java @@ -24,17 +24,25 @@ import org.eclipse.leshan.server.queue.PresenceListener; import org.eclipse.leshan.server.registration.Registration; import org.eclipse.leshan.server.registration.RegistrationListener; import org.eclipse.leshan.server.registration.RegistrationUpdate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Component; import java.util.Collection; @Slf4j +@Component() +@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' )|| ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") public class LwM2mServerListener { + private LeshanServer lhServer; - private LwM2MTransportService service; - public LwM2mServerListener(LeshanServer lhServer, LwM2MTransportService service) { + @Autowired + private LwM2MTransportServiceImpl service; + + public LwM2mServerListener init(LeshanServer lhServer) { this.lhServer = lhServer; - this.service = service; + return this; } public final RegistrationListener registrationListener = new RegistrationListener() { @@ -96,8 +104,7 @@ public class LwM2mServerListener { try { service.onObservationResponse(registration, observation.getPath().toString(), response); } catch (Exception e) { - e.printStackTrace(); - log.error("onResponse"); + log.error("[{}] onResponse", e.toString()); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java index 6519b5cd33..d48e3e4c9e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java @@ -27,7 +27,7 @@ import org.eclipse.leshan.server.registration.Registration; import org.eclipse.leshan.server.security.SecurityInfo; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; -import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportService; +import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportServiceImpl; import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import java.util.Map; @@ -48,7 +48,7 @@ public class LwM2MClient implements Cloneable { private UUID sessionUuid; private UUID profileUuid; private LeshanServer lwServer; - private LwM2MTransportService lwM2MTransportService; + private LwM2MTransportServiceImpl lwM2MTransportServiceImpl; private Registration registration; private ValidateDeviceCredentialsResponseMsg credentialsResponse; private Map attributes; @@ -92,7 +92,7 @@ public class LwM2MClient implements Cloneable { this.pendingRequests.remove(path); if (this.pendingRequests.size() == 0) { this.initValue(); - this.lwM2MTransportService.putDelayedUpdateResourcesThingsboard(this); + this.lwM2MTransportServiceImpl.putDelayedUpdateResourcesThingsboard(this); } } @@ -123,7 +123,7 @@ public class LwM2MClient implements Cloneable { public void onSuccessOrErrorDelayedRequests(String path) { if (path != null) this.delayedRequests.remove(path); if (this.delayedRequests.size() == 0 && this.getDelayedRequestsId().size() == 0) { - this.lwM2MTransportService.updatesAndSentModelParameter(this); + this.lwM2MTransportServiceImpl.updatesAndSentModelParameter(this); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2MSetSecurityStoreServer.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2MSetSecurityStoreServer.java deleted file mode 100644 index 7e2a9960d1..0000000000 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2MSetSecurityStoreServer.java +++ /dev/null @@ -1,241 +0,0 @@ -/** - * Copyright © 2016-2020 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.thingsboard.server.transport.lwm2m.server.secure; - -import lombok.Data; -import lombok.extern.slf4j.Slf4j; -import org.eclipse.leshan.core.util.Hex; -import org.eclipse.leshan.server.californium.LeshanServerBuilder; -import org.eclipse.leshan.server.redis.RedisRegistrationStore; -import org.eclipse.leshan.server.redis.RedisSecurityStore; -import org.eclipse.leshan.server.security.DefaultAuthorizer; -import org.eclipse.leshan.server.security.EditableSecurityStore; -import org.eclipse.leshan.server.security.SecurityChecker; -import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode; -import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportContextServer; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.JedisPool; -import redis.clients.jedis.util.Pool; - -import java.math.BigInteger; -import java.net.URI; -import java.net.URISyntaxException; -import java.security.KeyStore; -import java.security.PublicKey; -import java.security.PrivateKey; -import java.security.AlgorithmParameters; -import java.security.KeyFactory; -import java.security.GeneralSecurityException; -import java.security.KeyStoreException; -import java.security.cert.X509Certificate; -import java.security.interfaces.ECPublicKey; -import java.security.spec.ECGenParameterSpec; -import java.security.spec.ECParameterSpec; -import java.security.spec.ECPoint; -import java.security.spec.ECPrivateKeySpec; -import java.security.spec.ECPublicKeySpec; -import java.security.spec.KeySpec; -import java.util.Arrays; - -import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.REDIS; -import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.X509; - - -@Slf4j -@Data -public class LwM2MSetSecurityStoreServer { - - private KeyStore keyStore; - private X509Certificate certificate; - private PublicKey publicKey; - private PrivateKey privateKey; - private LwM2MTransportContextServer context; - private LwM2mInMemorySecurityStore lwM2mInMemorySecurityStore; - - private LeshanServerBuilder builder; - EditableSecurityStore securityStore; - - public LwM2MSetSecurityStoreServer(LeshanServerBuilder builder, LwM2MTransportContextServer context, LwM2mInMemorySecurityStore lwM2mInMemorySecurityStore, LwM2MSecurityMode dtlsMode) { - this.builder = builder; - this.context = context; - this.lwM2mInMemorySecurityStore = lwM2mInMemorySecurityStore; - /** Set securityStore with new registrationStore */ - switch (dtlsMode) { - /** Use PSK only */ - case PSK: - generatePSK_RPK(); - if (this.privateKey != null && this.privateKey.getEncoded().length > 0) { - builder.setPrivateKey(this.privateKey); - builder.setPublicKey(null); - getParamsPSK(); - } - break; - /** Use RPK only */ - case RPK: - generatePSK_RPK(); - if (this.publicKey != null && this.publicKey.getEncoded().length > 0 && - this.privateKey != null && this.privateKey.getEncoded().length > 0) { - builder.setPublicKey(this.publicKey); - builder.setPrivateKey(this.privateKey); - getParamsRPK(); - } - break; - /** Use x509 only */ - case X509: - setServerWithX509Cert(); - break; - /** No security */ - case NO_SEC: - builder.setTrustedCertificates(new X509Certificate[0]); - break; - /** Use x509 with EST */ - case X509_EST: - // TODO support sentinel pool and make pool configurable - break; - case REDIS: - /** - * Set securityStore with new registrationStore (if use redis store) - * Connect to redis - */ - Pool jedis = null; - try { - jedis = new JedisPool(new URI(this.context.getCtxServer().getRedisUrl())); - securityStore = new RedisSecurityStore(jedis); - builder.setRegistrationStore(new RedisRegistrationStore(jedis)); - } catch (URISyntaxException e) { - e.printStackTrace(); - } - break; - default: - } - - /** Set securityStore with new registrationStore (if not redis)*/ - if (dtlsMode.code < REDIS.code) { - securityStore = lwM2mInMemorySecurityStore; - if (dtlsMode == X509) { - builder.setAuthorizer(new DefaultAuthorizer(securityStore, new SecurityChecker() { - @Override - protected boolean matchX509Identity(String endpoint, String receivedX509CommonName, - String expectedX509CommonName) { - return endpoint.startsWith(expectedX509CommonName); - } - })); - } - } - - /** Set securityStore with new registrationStore */ - builder.setSecurityStore(securityStore); - } - - private void generatePSK_RPK() { - try { - /** Get Elliptic Curve Parameter spec for secp256r1 */ - AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC"); - algoParameters.init(new ECGenParameterSpec("secp256r1")); - ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class); - if (this.context.getCtxServer().getServerPublicX() != null && !this.context.getCtxServer().getServerPublicX().isEmpty() && this.context.getCtxServer().getServerPublicY() != null && !this.context.getCtxServer().getServerPublicY().isEmpty()) { - /** Get point values */ - byte[] publicX = Hex.decodeHex(this.context.getCtxServer().getServerPublicX().toCharArray()); - byte[] publicY = Hex.decodeHex(this.context.getCtxServer().getServerPublicY().toCharArray()); - /** Create key specs */ - KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)), - parameterSpec); - /** Get keys */ - this.publicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec); - } - if (this.context.getCtxServer().getServerPrivateS() != null && !this.context.getCtxServer().getServerPrivateS().isEmpty()) { - /** Get point values */ - byte[] privateS = Hex.decodeHex(this.context.getCtxServer().getServerPrivateS().toCharArray()); - /** Create key specs */ - KeySpec privateKeySpec = new ECPrivateKeySpec(new BigInteger(privateS), parameterSpec); - /** Get keys */ - this.privateKey = KeyFactory.getInstance("EC").generatePrivate(privateKeySpec); - } - } catch (GeneralSecurityException | IllegalArgumentException e) { - log.error("[{}] Failed generate Server PSK/RPK", e.getMessage()); - throw new RuntimeException(e); - } - } - - private void setServerWithX509Cert() { - try { - if (this.context.getCtxServer().getKeyStoreValue() != null) { - setBuilderX509(); - X509Certificate rootCAX509Cert = (X509Certificate) this.context.getCtxServer().getKeyStoreValue().getCertificate(this.context.getCtxServer().getRootAlias()); - if (rootCAX509Cert != null) { - X509Certificate[] trustedCertificates = new X509Certificate[1]; - trustedCertificates[0] = rootCAX509Cert; - builder.setTrustedCertificates(trustedCertificates); - } else { - /** by default trust all */ - builder.setTrustedCertificates(new X509Certificate[0]); - } - } - else { - /** by default trust all */ - this.builder.setTrustedCertificates(new X509Certificate[0]); - log.error("Unable to load X509 files for LWM2MServer"); - } - } catch (KeyStoreException ex) { - log.error("[{}] Unable to load X509 files server", ex.getMessage()); - } - } - - private void setBuilderX509() { - /** - * For deb => KeyStorePathFile == yml or commandline: KEY_STORE_PATH_FILE - * For idea => KeyStorePathResource == common/transport/lwm2m/src/main/resources/credentials: in LwM2MTransportContextServer: credentials/serverKeyStore.jks - */ - try { - X509Certificate serverCertificate = (X509Certificate) this.context.getCtxServer().getKeyStoreValue().getCertificate(this.context.getCtxServer().getServerAlias()); - PrivateKey privateKey = (PrivateKey) this.context.getCtxServer().getKeyStoreValue().getKey(this.context.getCtxServer().getServerAlias(), this.context.getCtxServer().getKeyStorePasswordServer() == null ? null : this.context.getCtxServer().getKeyStorePasswordServer().toCharArray()); - this.builder.setPrivateKey(privateKey); - this.builder.setCertificateChain(new X509Certificate[]{serverCertificate}); - } catch (Exception ex) { - log.error("[{}] Unable to load KeyStore files server", ex.getMessage()); - } - } - - private void getParamsPSK() { - log.info("\nServer uses PSK -> private key : \n security key : [{}] \n serverSecureURI : [{}]", - Hex.encodeHexString(this.privateKey.getEncoded()), - this.context.getCtxServer().getServerSecureHost() + ":" + Integer.toString(this.context.getCtxServer().getServerSecurePort())); - } - - private void getParamsRPK() { - if (this.publicKey instanceof ECPublicKey) { - /** Get x coordinate */ - byte[] x = ((ECPublicKey) this.publicKey).getW().getAffineX().toByteArray(); - if (x[0] == 0) - x = Arrays.copyOfRange(x, 1, x.length); - - /** Get Y coordinate */ - byte[] y = ((ECPublicKey) this.publicKey).getW().getAffineY().toByteArray(); - if (y[0] == 0) - y = Arrays.copyOfRange(y, 1, y.length); - - /** Get Curves params */ - String params = ((ECPublicKey) this.publicKey).getParams().toString(); - log.info( - " \nServer uses RPK : \n Elliptic Curve parameters : [{}] \n Public x coord : [{}] \n Public y coord : [{}] \n Public Key (Hex): [{}] \n Private Key (Hex): [{}]", - params, Hex.encodeHexString(x), Hex.encodeHexString(y), - Hex.encodeHexString(this.publicKey.getEncoded()), - Hex.encodeHexString(this.privateKey.getEncoded())); - } else { - throw new IllegalStateException("Unsupported Public Key Format (only ECPublicKey supported)."); - } - } -} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java index ad8dd4b0f8..fb90b1537c 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java @@ -25,32 +25,32 @@ import org.eclipse.leshan.server.security.SecurityInfo; import org.eclipse.leshan.server.security.SecurityStoreListener; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; -import org.springframework.stereotype.Component; +import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.transport.lwm2m.secure.LwM2MGetSecurityInfo; +import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode; +import org.thingsboard.server.transport.lwm2m.secure.LwM2mValidateCredentialsSecurityInfo; import org.thingsboard.server.transport.lwm2m.secure.ReadResultSecurityStore; import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler; import org.thingsboard.server.transport.lwm2m.server.client.AttrTelemetryObserveValue; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import org.thingsboard.server.transport.lwm2m.utils.TypeServer; -import java.util.Map; -import java.util.UUID; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.stream.Collectors; -import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.DEFAULT_MODE; import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.NO_SEC; @Slf4j -@Component("LwM2mInMemorySecurityStore") +@Service("LwM2mInMemorySecurityStore") @ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' )|| ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") public class LwM2mInMemorySecurityStore extends InMemorySecurityStore { // lock for the two maps @@ -63,26 +63,36 @@ public class LwM2mInMemorySecurityStore extends InMemorySecurityStore { private SecurityStoreListener listener; @Autowired - LwM2MGetSecurityInfo lwM2MGetSecurityInfo; + LwM2mValidateCredentialsSecurityInfo lwM2MValidateCredentialsSecurityInfo; + /** + * Start after DefaultAuthorizer or LwM2mPskStore + * @param endPoint - + * @return SecurityInfo + */ @Override public SecurityInfo getByEndpoint(String endPoint) { readLock.lock(); try { String registrationId = this.getByRegistrationId(endPoint, null); - SecurityInfo info = (registrationId != null && sessions.size() > 0 && sessions.get(registrationId) != null) ? sessions.get(registrationId).getInfo() : this.add(endPoint); + SecurityInfo info = (registrationId != null && sessions.size() > 0 && sessions.get(registrationId) != null) ? sessions.get(registrationId).getInfo() : this.addLwM2MClientToSession(endPoint); return info; } finally { readLock.unlock(); } } + /** + * Start after LwM2mPskStore + * @param identity - + * @return SecurityInfo + */ @Override public SecurityInfo getByIdentity(String identity) { readLock.lock(); try { String integrationId = this.getByRegistrationId(null, identity); - return (integrationId != null) ? sessions.get(integrationId).getInfo() : add(identity); + return (integrationId != null) ? sessions.get(integrationId).getInfo() : this.addLwM2MClientToSession(identity); } finally { readLock.unlock(); } @@ -141,11 +151,19 @@ public class LwM2mInMemorySecurityStore extends InMemorySecurityStore { return this.getSession(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())).entrySet().iterator().next().getValue(); } + + /** + * Update in sessions (LwM2MClient for key registration_Id) after starting registration LwM2MClient in LwM2MTransportServiceImpl + * Remove from sessions LwM2MClient with key registration_Endpoint + * @param lwServer - + * @param registration - + * @return LwM2MClient after adding it to session + */ public LwM2MClient updateInSessionsLwM2MClient(LeshanServer lwServer, Registration registration) { writeLock.lock(); try { if (this.sessions.get(registration.getEndpoint()) == null) { - this.add(registration.getEndpoint()); + this.addLwM2MClientToSession(registration.getEndpoint()); } LwM2MClient lwM2MClient = this.sessions.get(registration.getEndpoint()); lwM2MClient.setLwServer(lwServer); @@ -166,45 +184,43 @@ public class LwM2mInMemorySecurityStore extends InMemorySecurityStore { return (registrationIds != null && registrationIds.size() > 0) ? registrationIds.get(0) : null; } - public String getByRegistrationId(String credentialsId) { - List registrationIds = (this.sessions.entrySet().stream().filter(model -> credentialsId.equals(model.getValue().getEndPoint())).map(model -> model.getKey()).collect(Collectors.toList()).size() > 0) ? - this.sessions.entrySet().stream().filter(model -> credentialsId.equals(model.getValue().getEndPoint())).map(model -> model.getKey()).collect(Collectors.toList()) : - this.sessions.entrySet().stream().filter(model -> credentialsId.equals(model.getValue().getIdentity())).map(model -> model.getKey()).collect(Collectors.toList()); - return (registrationIds != null && registrationIds.size() > 0) ? registrationIds.get(0) : null; - } - public Registration getByRegistration(String registrationId) { return this.sessions.get(registrationId).getRegistration(); } - private SecurityInfo add(String identity) { - ReadResultSecurityStore store = lwM2MGetSecurityInfo.getSecurityInfo(identity, TypeServer.CLIENT); - UUID profileUuid = (store.getDeviceProfile() != null && addUpdateProfileParameters(store.getDeviceProfile())) ? store.getDeviceProfile().getUuidId() : null; - if (store.getSecurityInfo() != null) { - if (store.getSecurityMode() < DEFAULT_MODE.code) { + /** + * Add new LwM2MClient to session + * @param identity- + * @return SecurityInfo. If error - SecurityInfoError + * and log: + * - FORBIDDEN - if there is no authorization + * - profileUuid - if the device does not have a profile + * - device - if the thingsboard does not have a device with a name equal to the identity + */ + private SecurityInfo addLwM2MClientToSession(String identity) { + ReadResultSecurityStore store = lwM2MValidateCredentialsSecurityInfo.validateCredentialsSecurityInfo(identity, TypeServer.CLIENT); + if (store.getSecurityMode() < LwM2MSecurityMode.DEFAULT_MODE.code) { + UUID profileUuid = (store.getDeviceProfile() != null && addUpdateProfileParameters(store.getDeviceProfile())) ? store.getDeviceProfile().getUuidId() : null; + if (store.getSecurityInfo() != null && profileUuid != null) { String endpoint = store.getSecurityInfo().getEndpoint(); -// sessions.put(endpoint, new LwM2MClient(endpoint, store.getSecurityInfo().getIdentity(), store.getSecurityInfo(), store.getMsg(), null, null, profileUuid)); sessions.put(endpoint, new LwM2MClient(endpoint, store.getSecurityInfo().getIdentity(), store.getSecurityInfo(), store.getMsg(), null, profileUuid)); - } - } else { - if (store.getSecurityMode() == NO_SEC.code && profileUuid != null) -// sessions.put(identity, new LwM2MClient(identity, null, null, store.getMsg(), null, null, profileUuid)); + } else if (store.getSecurityMode() == NO_SEC.code && profileUuid != null) { sessions.put(identity, new LwM2MClient(identity, null, null, store.getMsg(), null, profileUuid)); - else { - log.error("Registration failed: FORBIDDEN/profileUuid/device [{}] , endpointId: [{}]", profileUuid, identity); - /** - * Return Error securityInfo - */ - byte[] preSharedKey = Hex.decodeHex("0A0B".toCharArray()); - SecurityInfo info = SecurityInfo.newPreSharedKeyInfo("error", "error_identity", preSharedKey); - return info; + } else { + log.error("Registration failed: FORBIDDEN/profileUuid/device [{}] , endpointId: [{}]", profileUuid, identity); + /** + * Return Error securityInfo + */ + byte[] preSharedKey = Hex.decodeHex("0A0B".toCharArray()); + SecurityInfo infoError = SecurityInfo.newPreSharedKeyInfo("error", "error_identity", preSharedKey); + return infoError; + } } - } - return store.getSecurityInfo(); + return store.getSecurityInfo(); } - public Map getSession (UUID sessionUuId){ - return this.sessions.entrySet().stream().filter(e -> e.getValue().getSessionUuid().equals(sessionUuId)).collect(Collectors.toMap(map -> map.getKey(), map -> map.getValue())); + public Map getSession(UUID sessionUuId) { + return this.sessions.entrySet().stream().filter(e -> e.getValue().getSessionUuid().equals(sessionUuId)).collect(Collectors.toMap(map -> map.getKey(), map -> map.getValue())); } public Map getSessions() { @@ -219,13 +235,10 @@ public class LwM2mInMemorySecurityStore extends InMemorySecurityStore { return this.profiles.get(profileUuId); } - public MapsetProfiles(Map profiles) { + public Map setProfiles(Map profiles) { return this.profiles = profiles; } - /** - * @param deviceProfile - */ public boolean addUpdateProfileParameters(DeviceProfile deviceProfile) { JsonObject profilesConfigData = LwM2MTransportHandler.getObserveAttrTelemetryFromThingsboard(deviceProfile); if (profilesConfigData != null) { @@ -233,5 +246,4 @@ public class LwM2mInMemorySecurityStore extends InMemorySecurityStore { } return (profilesConfigData != null); } - } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java index cca1effae4..4a52124af9 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java @@ -129,7 +129,6 @@ public class LwM2mValueConverterImpl implements LwM2mValueConverter { case FLOAT: return String.valueOf(value); case TIME: -// return Long.toString(((Date) value).getTime()); String DATE_FORMAT = "MMM d, yyyy HH:mm a"; Long timeValue = ((Date) value).getTime(); DateFormat formatter = new SimpleDateFormat(DATE_FORMAT); diff --git a/netty-mqtt/pom.xml b/netty-mqtt/pom.xml index 793ea83373..bcf36485a9 100644 --- a/netty-mqtt/pom.xml +++ b/netty-mqtt/pom.xml @@ -67,11 +67,6 @@ org.apache.maven.plugins maven-compiler-plugin - 3.1 - - 1.8 - 1.8 - org.apache.maven.plugins @@ -87,4 +82,4 @@ - \ No newline at end of file + diff --git a/pom.xml b/pom.xml index 4522ea51bf..3cbd57e508 100755 --- a/pom.xml +++ b/pom.xml @@ -579,7 +579,7 @@ org.apache.maven.plugins maven-compiler-plugin - 2.5.1 + 3.8.1 1.8 1.8 From be4475c2cc61935bdb73c76fa97cd1fa8cfef768 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 5 Jan 2021 19:06:14 +0200 Subject: [PATCH 021/249] Lwm2m: backEnd: refactoring service --- .../secure/LwM2MBootstrapSecurityStore.java | 8 +- ...wM2mCredentialsSecurityInfoValidator.java} | 8 +- .../lwm2m/server/LwM2MTransportRequest.java | 7 +- .../LwM2MTransportServerConfiguration.java | 10 -- .../LwM2MTransportServerInitializer.java | 37 +++--- .../server/LwM2MTransportServiceImpl.java | 111 ++++++++++-------- .../lwm2m/server/LwM2mServerListener.java | 20 ++-- .../lwm2m/server/client/LwM2MClient.java | 4 +- .../lwm2m/server/client/ResourceValue.java | 4 +- .../secure/LwM2mInMemorySecurityStore.java | 31 ++--- 10 files changed, 113 insertions(+), 127 deletions(-) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/{LwM2mValidateCredentialsSecurityInfo.java => LwM2mCredentialsSecurityInfoValidator.java} (97%) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java index 6d21d48c65..75e6f78d35 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java @@ -32,7 +32,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Service; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode; -import org.thingsboard.server.transport.lwm2m.secure.LwM2mValidateCredentialsSecurityInfo; +import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; import org.thingsboard.server.transport.lwm2m.secure.ReadResultSecurityStore; import org.thingsboard.server.transport.lwm2m.server.LwM2MSessionMsgListener; import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportContextServer; @@ -60,7 +60,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { private final EditableBootstrapConfigStore bootstrapConfigStore; @Autowired - LwM2mValidateCredentialsSecurityInfo lwM2MValidateCredentialsSecurityInfo; + LwM2mCredentialsSecurityInfoValidator lwM2MCredentialsSecurityInfoValidator; @Autowired public LwM2MTransportContextServer context; @@ -72,7 +72,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { @Override public List getAllByEndpoint(String endPoint) { String endPointKey = endPoint; - ReadResultSecurityStore store = lwM2MValidateCredentialsSecurityInfo.validateCredentialsSecurityInfo(endPointKey, TypeServer.BOOTSTRAP); + ReadResultSecurityStore store = lwM2MCredentialsSecurityInfoValidator.createAndValidateCredentialsSecurityInfo(endPointKey, TypeServer.BOOTSTRAP); if (store.getBootstrapJsonCredential() != null && store.getSecurityMode() < LwM2MSecurityMode.DEFAULT_MODE.code) { /** add value to store from BootstrapJson */ this.setBootstrapConfigScurityInfo(store); @@ -96,7 +96,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { @Override public SecurityInfo getByIdentity(String identity) { - ReadResultSecurityStore store = lwM2MValidateCredentialsSecurityInfo.validateCredentialsSecurityInfo(identity, TypeServer.BOOTSTRAP); + ReadResultSecurityStore store = lwM2MCredentialsSecurityInfoValidator.createAndValidateCredentialsSecurityInfo(identity, TypeServer.BOOTSTRAP); if (store.getBootstrapJsonCredential() != null && store.getSecurityMode() < LwM2MSecurityMode.DEFAULT_MODE.code) { /** add value to store from BootstrapJson */ this.setBootstrapConfigScurityInfo(store); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mValidateCredentialsSecurityInfo.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java similarity index 97% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mValidateCredentialsSecurityInfo.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java index 0983f9c87f..80b4772378 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mValidateCredentialsSecurityInfo.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java @@ -47,7 +47,7 @@ import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.X5 @Slf4j @Component("LwM2MGetSecurityInfo") @ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' ) || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") -public class LwM2mValidateCredentialsSecurityInfo { +public class LwM2mCredentialsSecurityInfoValidator { @Autowired public LwM2MTransportContextServer contextS; @@ -62,7 +62,7 @@ public class LwM2mValidateCredentialsSecurityInfo { * @param keyValue - * @return ValidateDeviceCredentialsResponseMsg and SecurityInfo */ - public ReadResultSecurityStore validateCredentialsSecurityInfo(String endPoint, TypeServer keyValue) { + public ReadResultSecurityStore createAndValidateCredentialsSecurityInfo(String endPoint, TypeServer keyValue) { CountDownLatch latch = new CountDownLatch(1); final ReadResultSecurityStore[] resultSecurityStore = new ReadResultSecurityStore[1]; contextS.getTransportService().process(ValidateDeviceLwM2MCredentialsRequestMsg.newBuilder().setCredentialsId(endPoint).build(), @@ -79,7 +79,7 @@ public class LwM2mValidateCredentialsSecurityInfo { @Override public void onError(Throwable e) { - log.trace("[{}] [{}] Failed to process credentials PSK ", endPoint, e.toString()); + log.trace("[{}] [{}] Failed to process credentials ", endPoint, e); resultSecurityStore[0] = createSecurityInfo(endPoint, null, null); latch.countDown(); } @@ -87,7 +87,7 @@ public class LwM2mValidateCredentialsSecurityInfo { try { latch.await(contextS.getCtxServer().getTimeout(), TimeUnit.MILLISECONDS); } catch (InterruptedException e) { - log.error("", e); + log.error("Failed to await credentials!", e); } return resultSecurityStore[0]; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java index bc7cbd5b46..de03e25767 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java @@ -88,13 +88,12 @@ public class LwM2MTransportRequest { @Autowired LwM2MTransportServiceImpl service; - @PostConstruct public void init() { this.converter = LwM2mValueConverterImpl.getInstance(); - executorResponse = Executors.newCachedThreadPool( + executorResponse = Executors.newFixedThreadPool(10, new NamedThreadFactory(String.format("LwM2M %s channel response", RESPONSE_CHANNEL))); - executorResponseError = Executors.newCachedThreadPool( + executorResponseError = Executors.newFixedThreadPool(10, new NamedThreadFactory(String.format("LwM2M %s channel response Error", RESPONSE_CHANNEL))); } @@ -220,7 +219,7 @@ public class LwM2MTransportRequest { if (request != null) { this.sendRequest(lwServer, registration, request, lwM2MClient, timeoutInMs, isDelayedUpdate); - } else if (request == null && isDelayedUpdate) { + } else if (isDelayedUpdate) { String msg = String.format(LOG_LW2M_ERROR + ": sendRequest: Resource path - %s msg No SendRequest to Client", target); service.sentLogsToThingsboard(msg, registration); log.error("[{}] - [{}] No SendRequest", target); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerConfiguration.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerConfiguration.java index ac2221054c..c809491803 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerConfiguration.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerConfiguration.java @@ -82,16 +82,6 @@ public class LwM2MTransportServerConfiguration { @Autowired private LwM2mInMemorySecurityStore lwM2mInMemorySecurityStore; - @Bean - public LwM2mServerListener lwM2mServerListenerCert() { - return new LwM2mServerListener(); - } - - @Bean - public LwM2mServerListener lwM2mServerListenerNoSecPskRpk() { - return new LwM2mServerListener(); - } - @Primary @Bean(name = "LeshanServerCert") public LeshanServer getLeshanServerCert() { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerInitializer.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerInitializer.java index 36d39130a3..da4cdbf634 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerInitializer.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerInitializer.java @@ -32,6 +32,10 @@ import javax.annotation.PreDestroy; @ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' ) || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") public class LwM2MTransportServerInitializer { + + @Autowired + private LwM2MTransportServiceImpl service; + @Autowired @Qualifier("LeshanServerCert") private LeshanServer lhServerCert; @@ -39,16 +43,6 @@ public class LwM2MTransportServerInitializer { @Autowired @Qualifier("LeshanServerNoSecPskRpk") private LeshanServer lhServerNoSecPskRpk; -// -// @Autowired -// @Qualifier("LeshanServerListener") -// private LwM2mServerListener lwM2mServerListener; - - @Autowired - private LwM2mServerListener lwM2mServerListenerNoSecPskRpk; - - @Autowired - private LwM2mServerListener lwM2mServerListenerCert; @Autowired private LwM2MTransportContextServer context; @@ -70,28 +64,25 @@ public class LwM2MTransportServerInitializer { private void startLhServerCert() { this.lhServerCert.start(); - LwM2mServerListener serverListenerCert = this.lwM2mServerListenerCert.init(this.lhServerCert); - this.lhServerCert.getRegistrationService().addListener(serverListenerCert.registrationListener); - this.lhServerCert.getPresenceService().addListener(serverListenerCert.presenceListener); - this.lhServerCert.getObservationService().addListener(serverListenerCert.observationListener); + LwM2mServerListener lhServerCertListener = new LwM2mServerListener(this.lhServerCert, service); + this.lhServerCert.getRegistrationService().addListener(lhServerCertListener.registrationListener); + this.lhServerCert.getPresenceService().addListener(lhServerCertListener.presenceListener); + this.lhServerCert.getObservationService().addListener(lhServerCertListener.observationListener); } private void startLhServerNoSecPskRpk() { this.lhServerNoSecPskRpk.start(); - LwM2mServerListener serverListenerNoSecPskRpk = this.lwM2mServerListenerNoSecPskRpk.init(this.lhServerNoSecPskRpk); - this.lhServerNoSecPskRpk.getRegistrationService().addListener(serverListenerNoSecPskRpk.registrationListener); - this.lhServerNoSecPskRpk.getPresenceService().addListener(serverListenerNoSecPskRpk.presenceListener); - this.lhServerNoSecPskRpk.getObservationService().addListener(serverListenerNoSecPskRpk.observationListener); + LwM2mServerListener lhServerNoSecPskRpkListener = new LwM2mServerListener(this.lhServerNoSecPskRpk, service); + this.lhServerNoSecPskRpk.getRegistrationService().addListener(lhServerNoSecPskRpkListener.registrationListener); + this.lhServerNoSecPskRpk.getPresenceService().addListener(lhServerNoSecPskRpkListener.presenceListener); + this.lhServerNoSecPskRpk.getObservationService().addListener(lhServerNoSecPskRpkListener.observationListener); } @PreDestroy public void shutdown() { log.info("Stopping LwM2M transport Server!"); - try { - lhServerCert.destroy(); - lhServerNoSecPskRpk.destroy(); - } finally { - } + lhServerCert.destroy(); + lhServerNoSecPskRpk.destroy(); log.info("LwM2M transport Server stopped!"); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServiceImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServiceImpl.java index 2a6af4e19e..c4575c1a8f 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServiceImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServiceImpl.java @@ -20,6 +20,7 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.Link; import org.eclipse.leshan.core.model.ResourceModel; import org.eclipse.leshan.core.node.LwM2mMultipleResource; import org.eclipse.leshan.core.node.LwM2mObject; @@ -56,7 +57,6 @@ import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import javax.annotation.PostConstruct; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.LinkedHashSet; @@ -68,7 +68,6 @@ import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; @@ -80,7 +79,6 @@ import java.util.stream.Collectors; 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.DEFAULT_TIMEOUT; 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; @@ -122,11 +120,11 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { @PostConstruct public void init() { this.context.getScheduler().scheduleAtFixedRate(this::checkInactivityAndReportActivity, new Random().nextInt((int) context.getCtxServer().getSessionReportTimeout()), context.getCtxServer().getSessionReportTimeout(), TimeUnit.MILLISECONDS); - this.executorRegistered = Executors.newCachedThreadPool( + this.executorRegistered = Executors.newFixedThreadPool(10, new NamedThreadFactory(String.format("LwM2M %s channel registered", SERVICE_CHANNEL))); - this.executorUpdateRegistered = Executors.newCachedThreadPool( + this.executorUpdateRegistered = Executors.newFixedThreadPool(10, new NamedThreadFactory(String.format("LwM2M %s channel update registered", SERVICE_CHANNEL))); - this.executorUnRegistered = Executors.newCachedThreadPool( + this.executorUnRegistered = Executors.newFixedThreadPool(10, new NamedThreadFactory(String.format("LwM2M %s channel un registered", SERVICE_CHANNEL))); this.converter = LwM2mValueConverterImpl.getInstance(); } @@ -149,7 +147,7 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { public void onRegistered(LeshanServer lwServer, Registration registration, Collection previousObsersations) { executorRegistered.submit(() -> { try { - log.info("[{}] [{{}] Client: create after Registration", registration.getEndpoint(), registration.getId()); + log.warn("[{}] [{{}] Client: create after Registration", registration.getEndpoint(), registration.getId()); LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.updateInSessionsLwM2MClient(lwServer, registration); if (lwM2MClient != null) { lwM2MClient.setLwM2MTransportServiceImpl(this); @@ -180,6 +178,7 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { /** * if sessionInfo removed from sessions, then new registerAsyncSession + * * @param lwServer - LeshanServer * @param registration - Registration LwM2M Client */ @@ -280,20 +279,38 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { * @param lwM2MClient - object with All parameters off client */ private void setLwM2MClient(LeshanServer lwServer, Registration registration, LwM2MClient lwM2MClient) { - Arrays.stream(registration.getObjectLinks()).forEach(url -> { + // #1 + for (Link url : registration.getObjectLinks()) { LwM2mPath pathIds = new LwM2mPath(url.getUrl()); if (pathIds.isObjectInstance() && !pathIds.isResource()) { lwM2MClient.getPendingRequests().add(url.getUrl()); } - }); + } // #2 - Arrays.stream(registration.getObjectLinks()).forEach(url -> { + for (Link url : registration.getObjectLinks()) { LwM2mPath pathIds = new LwM2mPath(url.getUrl()); if (pathIds.isObjectInstance() && !pathIds.isResource()) { lwM2MTransportRequest.sendAllRequest(lwServer, registration, url.getUrl(), GET_TYPE_OPER_READ, ContentFormat.TLV.getName(), lwM2MClient, null, null, this.context.getCtxServer().getTimeout(), false); } - }); + } + + // #1 +// Arrays.stream(registration.getObjectLinks()).forEach(url -> { +// LwM2mPath pathIds = new LwM2mPath(url.getUrl()); +// if (pathIds.isObjectInstance() && !pathIds.isResource()) { +// lwM2MClient.getPendingRequests().add(url.getUrl()); +// } +// }); + // #2 + +// Arrays.stream(registration.getObjectLinks()).forEach(url -> { +// LwM2mPath pathIds = new LwM2mPath(url.getUrl()); +// if (pathIds.isObjectInstance() && !pathIds.isResource()) { +// lwM2MTransportRequest.sendAllRequest(lwServer, registration, url.getUrl(), GET_TYPE_OPER_READ, ContentFormat.TLV.getName(), +// lwM2MClient, null, null, this.context.getCtxServer().getTimeout(), false); +// } +// }); } /** @@ -302,18 +319,17 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { */ private SessionInfoProto getValidateSessionInfo(Registration registration) { LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClientWithReg(registration, null); - return getNewSessionInfoProto(lwM2MClient); + return getNewSessionInfoProto(lwM2MClient); } /** - * * @param registrationId - * @return - */ private SessionInfoProto getValidateSessionInfo(String registrationId) { LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClientWithReg(null, registrationId); - return getNewSessionInfoProto(lwM2MClient); + return getNewSessionInfoProto(lwM2MClient); } private SessionInfoProto getNewSessionInfoProto(LwM2MClient lwM2MClient) { @@ -437,6 +453,7 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { /** * Get names and keyNames from profile shared!!!! attr resources IsWritable + * * @param lwM2MClient - * @return ArrayList keyNames from profile attr resources shared!!!! && IsWritable */ @@ -479,13 +496,13 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { } } // #1.2 - CountDownLatch cancelLatch = new CountDownLatch(1); - this.getParametersFromProfile(attributes, telemetries, registration, paths); - cancelLatch.countDown(); try { - cancelLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - log.error("[{}] updateAttrTelemetry", e.toString()); + writeLock.lock(); + this.getParametersFromProfile(attributes, telemetries, registration, paths); + } catch (Exception e) { + log.error("UpdateAttrTelemetry", e); + } finally { + writeLock.unlock(); } if (attributes.getAsJsonObject().entrySet().size() > 0) this.updateParametersOnThingsboard(attributes, DEVICE_ATTRIBUTES_TOPIC, registration); @@ -559,8 +576,8 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { /** * Prepare Sent to Thigsboard callback - Attribute or Telemetry * - * @param msg - JsonArray: [{name: value}] - * @param topicName - Api Attribute or Telemetry + * @param msg - JsonArray: [{name: value}] + * @param topicName - Api Attribute or Telemetry * @param registration - Id of Registration LwM2M Client */ public void updateParametersOnThingsboard(JsonElement msg, String topicName, Registration registration) { @@ -618,14 +635,7 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { * {@code ObservationService#cancelObservation()} */ public void setCancelObservationRecourse(LeshanServer lwServer, Registration registration, String path) { - CountDownLatch cancelLatch = new CountDownLatch(1); lwServer.getObservationService().cancelObservations(registration, path); - cancelLatch.countDown(); - try { - cancelLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - log.error("", e); - } } /** @@ -685,30 +695,28 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { boolean isChange = false; try { writeLock.lock(); - try { - // #1 - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClientWithReg(registration, null); - LwM2mPath pathIds = new LwM2mPath(path); - log.warn("#0 nameDevice: [{}] resultIds: [{}] value: [{}], values: [{}] ", lwM2MClient.getDeviceName(), pathIds, value, values); - ResourceModel.Type resModelType = context.getCtxServer().getResourceModelType(registration, pathIds); - ResourceValue resValueOld = lwM2MClient.getResources().get(path); - // #2 - if (resValueOld.isMultiInstances() && !values.toString().equals(resValueOld.getResourceValue().toString())) { - ResourceValue resourceValue = new ResourceValue(values, null, true); - lwM2MClient.getResources().put(path, resourceValue); - isChange = true; - } else if (!LwM2MTransportHandler.equalsResourceValue(resValueOld.getValue(), value, resModelType, pathIds)) { - ResourceValue resourceValue = new ResourceValue(null, value, false); - lwM2MClient.getResources().put(path, resourceValue); - isChange = true; - } - } finally { - writeLock.unlock(); + // #1 + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClientWithReg(registration, null); + LwM2mPath pathIds = new LwM2mPath(path); + log.warn("#0 nameDevice: [{}] resultIds: [{}] value: [{}], values: [{}] ", lwM2MClient.getDeviceName(), pathIds, value, values); + ResourceModel.Type resModelType = context.getCtxServer().getResourceModelType(registration, pathIds); + ResourceValue resValueOld = lwM2MClient.getResources().get(path); + // #2 + if (resValueOld.isMultiInstances() && !values.toString().equals(resValueOld.getResourceValue().toString())) { + ResourceValue resourceValue = new ResourceValue(values, null, true); + lwM2MClient.getResources().put(path, resourceValue); + isChange = true; + } else if (!LwM2MTransportHandler.equalsResourceValue(resValueOld.getValue(), value, resModelType, pathIds)) { + ResourceValue resourceValue = new ResourceValue(null, value, false); + lwM2MClient.getResources().put(path, resourceValue); + isChange = true; } + } catch (Exception e) { + log.error("#1_1 Update ResourcesValue after Observation is unsuccessfully path: [{}] value: [{}] [{}]", path, value, e.toString()); + } finally { + writeLock.unlock(); } - catch (Exception e) { - log.error("#1_1 Update ResourcesValue after Observation in CountDownLatch is unsuccessfully path: [{}] value: [{}] [{}]", path, value, e.toString()); - } + if (isChange) { Set paths = new HashSet<>(); paths.add(path); @@ -1103,6 +1111,7 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { /** * if sessionInfo removed from sessions, then new registerAsyncSession + * * @param sessionInfo - */ private void checkInactivity(SessionInfoProto sessionInfo) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java index 2028fb4f00..239a40658f 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java @@ -24,25 +24,18 @@ import org.eclipse.leshan.server.queue.PresenceListener; import org.eclipse.leshan.server.registration.Registration; import org.eclipse.leshan.server.registration.RegistrationListener; import org.eclipse.leshan.server.registration.RegistrationUpdate; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; -import org.springframework.stereotype.Component; import java.util.Collection; @Slf4j -@Component() -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' )|| ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") public class LwM2mServerListener { - private LeshanServer lhServer; + private final LeshanServer lhServer; + private final LwM2MTransportServiceImpl service; - @Autowired - private LwM2MTransportServiceImpl service; - - public LwM2mServerListener init(LeshanServer lhServer) { + public LwM2mServerListener(LeshanServer lhServer, LwM2MTransportServiceImpl service) { this.lhServer = lhServer; - return this; + this.service = service; } public final RegistrationListener registrationListener = new RegistrationListener() { @@ -51,8 +44,8 @@ public class LwM2mServerListener { */ @Override public void registered(Registration registration, Registration previousReg, - Collection previousObsersations) { - service.onRegistered(lhServer, registration, previousObsersations); + Collection previousObservations) { + service.onRegistered(lhServer, registration, previousObservations); } /** @@ -120,4 +113,5 @@ public class LwM2mServerListener { log.info("Received newObservation from [{}] endpoint [{}] ", observation.getPath(), registration.getEndpoint()); } }; + } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java index d48e3e4c9e..72cb052dc7 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java @@ -63,12 +63,12 @@ public class LwM2MClient implements Cloneable { return super.clone(); } - public LwM2MClient(String endPoint, String identity, SecurityInfo info, ValidateDeviceCredentialsResponseMsg credentialsResponse, Map attributes, UUID profileUuid) { + public LwM2MClient(String endPoint, String identity, SecurityInfo info, ValidateDeviceCredentialsResponseMsg credentialsResponse, UUID profileUuid) { this.endPoint = endPoint; this.identity = identity; this.info = info; this.credentialsResponse = credentialsResponse; - this.attributes = (attributes != null && attributes.size() > 0) ? attributes : new ConcurrentHashMap(); + this.attributes = new ConcurrentHashMap<>(); this.pendingRequests = ConcurrentHashMap.newKeySet(); this.delayedRequests = new ConcurrentHashMap<>(); this.resources = new ConcurrentHashMap<>(); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResourceValue.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResourceValue.java index d58890dfba..2c962a4395 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResourceValue.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResourceValue.java @@ -16,6 +16,7 @@ package org.thingsboard.server.transport.lwm2m.server.client; import lombok.Data; + import java.util.Map; @Data @@ -24,11 +25,12 @@ public class ResourceValue { Object value; boolean multiInstances; - public ResourceValue ( Map values, Object value, boolean multiInstances) { + public ResourceValue(Map values, Object value, boolean multiInstances) { this.values = values; this.value = value; this.multiInstances = multiInstances; } + public Object getResourceValue() { return this.multiInstances ? this.values : this.value; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java index fb90b1537c..088962cb71 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java @@ -29,7 +29,7 @@ import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode; -import org.thingsboard.server.transport.lwm2m.secure.LwM2mValidateCredentialsSecurityInfo; +import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; import org.thingsboard.server.transport.lwm2m.secure.ReadResultSecurityStore; import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler; import org.thingsboard.server.transport.lwm2m.server.client.AttrTelemetryObserveValue; @@ -53,17 +53,18 @@ import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.NO @Service("LwM2mInMemorySecurityStore") @ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' )|| ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") public class LwM2mInMemorySecurityStore extends InMemorySecurityStore { + private static final boolean INFOS_ARE_COMPROMISED = false; + // lock for the two maps - protected final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); - protected final Lock readLock = readWriteLock.readLock(); - protected final Lock writeLock = readWriteLock.writeLock(); - private final boolean infosAreCompromised = false; - protected Map sessions = new ConcurrentHashMap<>(); - protected Map profiles = new ConcurrentHashMap<>(); + private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); + private final Lock readLock = readWriteLock.readLock(); + private final Lock writeLock = readWriteLock.writeLock(); + private final Map sessions = new ConcurrentHashMap<>(); + private Map profiles = new ConcurrentHashMap<>(); private SecurityStoreListener listener; @Autowired - LwM2mValidateCredentialsSecurityInfo lwM2MValidateCredentialsSecurityInfo; + LwM2mCredentialsSecurityInfoValidator lwM2MCredentialsSecurityInfoValidator; /** * Start after DefaultAuthorizer or LwM2mPskStore @@ -75,8 +76,8 @@ public class LwM2mInMemorySecurityStore extends InMemorySecurityStore { readLock.lock(); try { String registrationId = this.getByRegistrationId(endPoint, null); - SecurityInfo info = (registrationId != null && sessions.size() > 0 && sessions.get(registrationId) != null) ? sessions.get(registrationId).getInfo() : this.addLwM2MClientToSession(endPoint); - return info; + return (registrationId != null && sessions.size() > 0 && sessions.get(registrationId) != null) ? + sessions.get(registrationId).getInfo() : this.addLwM2MClientToSession(endPoint); } finally { readLock.unlock(); } @@ -102,7 +103,7 @@ public class LwM2mInMemorySecurityStore extends InMemorySecurityStore { public Collection getAll() { readLock.lock(); try { - return Collections.unmodifiableCollection(this.sessions.entrySet().stream().map(model -> model.getValue().getInfo()).collect(Collectors.toList())); + return Collections.unmodifiableCollection(this.sessions.values().stream().map(LwM2MClient::getInfo).collect(Collectors.toList())); } finally { readLock.unlock(); } @@ -118,7 +119,7 @@ public class LwM2mInMemorySecurityStore extends InMemorySecurityStore { LwM2MClient lwM2MClient = (sessions.get(registrationId) != null) ? sessions.get(registrationId) : null; if (lwM2MClient != null) { if (listener != null) { - listener.securityInfoRemoved(infosAreCompromised, lwM2MClient.getInfo()); + listener.securityInfoRemoved(INFOS_ARE_COMPROMISED, lwM2MClient.getInfo()); } sessions.remove(registrationId); } @@ -198,14 +199,14 @@ public class LwM2mInMemorySecurityStore extends InMemorySecurityStore { * - device - if the thingsboard does not have a device with a name equal to the identity */ private SecurityInfo addLwM2MClientToSession(String identity) { - ReadResultSecurityStore store = lwM2MValidateCredentialsSecurityInfo.validateCredentialsSecurityInfo(identity, TypeServer.CLIENT); + ReadResultSecurityStore store = lwM2MCredentialsSecurityInfoValidator.createAndValidateCredentialsSecurityInfo(identity, TypeServer.CLIENT); if (store.getSecurityMode() < LwM2MSecurityMode.DEFAULT_MODE.code) { UUID profileUuid = (store.getDeviceProfile() != null && addUpdateProfileParameters(store.getDeviceProfile())) ? store.getDeviceProfile().getUuidId() : null; if (store.getSecurityInfo() != null && profileUuid != null) { String endpoint = store.getSecurityInfo().getEndpoint(); - sessions.put(endpoint, new LwM2MClient(endpoint, store.getSecurityInfo().getIdentity(), store.getSecurityInfo(), store.getMsg(), null, profileUuid)); + sessions.put(endpoint, new LwM2MClient(endpoint, store.getSecurityInfo().getIdentity(), store.getSecurityInfo(), store.getMsg(), profileUuid)); } else if (store.getSecurityMode() == NO_SEC.code && profileUuid != null) { - sessions.put(identity, new LwM2MClient(identity, null, null, store.getMsg(), null, profileUuid)); + sessions.put(identity, new LwM2MClient(identity, null, null, store.getMsg(), profileUuid)); } else { log.error("Registration failed: FORBIDDEN/profileUuid/device [{}] , endpointId: [{}]", profileUuid, identity); /** From e6a30ca03b47e31ff6693107363eab915c35bbb3 Mon Sep 17 00:00:00 2001 From: Viacheslav Kukhtyn Date: Fri, 8 Jan 2021 17:32:43 +0200 Subject: [PATCH 022/249] Add credentials for REST API call node --- .../credentials/AnonymousCredentials.java | 22 +++++++++++ .../engine/credentials/BasicCredentials.java | 26 +++++++++++++ .../CertPemCredentials.java} | 6 +-- .../engine/mqtt/TbMqttNodeConfiguration.java | 4 +- .../engine/mqtt/azure/TbAzureIotHubNode.java | 6 +-- .../azure/TbAzureIotHubNodeConfiguration.java | 3 -- ...als.java => MqttAnonymousCredentials.java} | 12 +----- ...entials.java => MqttBasicCredentials.java} | 23 ++--------- .../credentials/MqttCertPemCredentials.java | 21 ++++++++++ .../credentials/MqttClientCredentials.java | 16 ++++---- .../rule/engine/rest/TbHttpClient.java | 9 ++++- .../rest/TbRestApiCallNodeConfiguration.java | 4 ++ .../credentials/HttpAnonymousCredentials.java | 21 ++++++++++ .../credentials/HttpBasicCredentials.java | 31 +++++++++++++++ .../credentials/HttpCertPemCredentials.java | 21 ++++++++++ .../credentials/HttpClientCredentials.java | 38 +++++++++++++++++++ .../credentials/HttpBasicCredentialsTest.java | 34 +++++++++++++++++ 17 files changed, 246 insertions(+), 51 deletions(-) create mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/AnonymousCredentials.java create mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/BasicCredentials.java rename rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/{mqtt/credentials/CertPemClientCredentials.java => credentials/CertPemCredentials.java} (98%) rename rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/{AnonymousCredentials.java => MqttAnonymousCredentials.java} (73%) rename rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/{BasicCredentials.java => MqttBasicCredentials.java} (66%) create mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttCertPemCredentials.java create mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpAnonymousCredentials.java create mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpBasicCredentials.java create mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpCertPemCredentials.java create mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpClientCredentials.java create mode 100644 rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/credentials/HttpBasicCredentialsTest.java diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/AnonymousCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/AnonymousCredentials.java new file mode 100644 index 0000000000..176899341b --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/AnonymousCredentials.java @@ -0,0 +1,22 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.credentials; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class AnonymousCredentials { +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/BasicCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/BasicCredentials.java new file mode 100644 index 0000000000..63eab59045 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/BasicCredentials.java @@ -0,0 +1,26 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.credentials; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.Data; + +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class BasicCredentials { + private String username; + private String password; +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/CertPemClientCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CertPemCredentials.java similarity index 98% rename from rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/CertPemClientCredentials.java rename to rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CertPemCredentials.java index df9f9f8275..055741584c 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/CertPemClientCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CertPemCredentials.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.rule.engine.mqtt.credentials; +package org.thingsboard.rule.engine.credentials; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import io.netty.handler.ssl.ClientAuth; @@ -55,8 +55,7 @@ import java.util.Optional; @Data @Slf4j @JsonIgnoreProperties(ignoreUnknown = true) -public class CertPemClientCredentials implements MqttClientCredentials { - +public class CertPemCredentials { private static final String TLS_VERSION = "TLSv1.2"; private String caCert; @@ -64,7 +63,6 @@ public class CertPemClientCredentials implements MqttClientCredentials { private String privateKey; private String password; - @Override public Optional initSslContext() { try { Security.addProvider(new BouncyCastleProvider()); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeConfiguration.java index 10e8ecb3b7..b90e43efd1 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeConfiguration.java @@ -17,7 +17,7 @@ package org.thingsboard.rule.engine.mqtt; import lombok.Data; import org.thingsboard.rule.engine.api.NodeConfiguration; -import org.thingsboard.rule.engine.mqtt.credentials.AnonymousCredentials; +import org.thingsboard.rule.engine.mqtt.credentials.MqttAnonymousCredentials; import org.thingsboard.rule.engine.mqtt.credentials.MqttClientCredentials; @Data @@ -42,7 +42,7 @@ public class TbMqttNodeConfiguration implements NodeConfiguration initSslContext() { - return Optional.empty(); - } +public class MqttAnonymousCredentials extends AnonymousCredentials implements MqttClientCredentials { } - diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/BasicCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttBasicCredentials.java similarity index 66% rename from rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/BasicCredentials.java rename to rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttBasicCredentials.java index fa0adbaca4..44eb18badc 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/BasicCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttBasicCredentials.java @@ -15,28 +15,13 @@ */ package org.thingsboard.rule.engine.mqtt.credentials; -import io.netty.handler.ssl.SslContext; -import lombok.Data; import org.thingsboard.mqtt.MqttClientConfig; +import org.thingsboard.rule.engine.credentials.BasicCredentials; -import java.util.Optional; - -@Data -public class BasicCredentials implements MqttClientCredentials { - - private String username; - private String password; - - @Override - public Optional initSslContext() { - return Optional.empty(); - } - +public class MqttBasicCredentials extends BasicCredentials implements MqttClientCredentials { @Override public void configure(MqttClientConfig config) { - config.setUsername(username); - config.setPassword(password); + config.setUsername(getUsername()); + config.setPassword(getPassword()); } - } - diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttCertPemCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttCertPemCredentials.java new file mode 100644 index 0000000000..0aef057601 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttCertPemCredentials.java @@ -0,0 +1,21 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.mqtt.credentials; + +import org.thingsboard.rule.engine.credentials.CertPemCredentials; + +public class MqttCertPemCredentials extends CertPemCredentials implements MqttClientCredentials { +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttClientCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttClientCredentials.java index 4814fb3afb..e5c08320f8 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttClientCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttClientCredentials.java @@ -23,18 +23,16 @@ import org.thingsboard.rule.engine.mqtt.azure.AzureIotHubSasCredentials; import java.util.Optional; -@JsonTypeInfo( - use = JsonTypeInfo.Id.NAME, - include = JsonTypeInfo.As.PROPERTY, - property = "type") +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") @JsonSubTypes({ - @JsonSubTypes.Type(value = AnonymousCredentials.class, name = "anonymous"), - @JsonSubTypes.Type(value = BasicCredentials.class, name = "basic"), + @JsonSubTypes.Type(value = MqttAnonymousCredentials.class, name = "anonymous"), + @JsonSubTypes.Type(value = MqttBasicCredentials.class, name = "basic"), @JsonSubTypes.Type(value = AzureIotHubSasCredentials.class, name = "sas"), - @JsonSubTypes.Type(value = CertPemClientCredentials.class, name = "cert.PEM")}) + @JsonSubTypes.Type(value = MqttCertPemCredentials.class, name = "cert.PEM")}) public interface MqttClientCredentials { - - Optional initSslContext(); + default Optional initSslContext() { + return Optional.empty(); + } default void configure(MqttClientConfig config) { } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java index f25d246a2e..08cda8e322 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java @@ -17,6 +17,7 @@ package org.thingsboard.rule.engine.rest; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContextBuilder; import lombok.Data; import lombok.extern.slf4j.Slf4j; @@ -133,7 +134,7 @@ public class TbHttpClient { } else { this.eventLoopGroup = new NioEventLoopGroup(); Netty4ClientHttpRequestFactory nettyFactory = new Netty4ClientHttpRequestFactory(this.eventLoopGroup); - nettyFactory.setSslContext(SslContextBuilder.forClient().build()); + nettyFactory.setSslContext(initSslContext()); nettyFactory.setReadTimeout(config.getReadTimeoutMs()); httpClient = new AsyncRestTemplate(nettyFactory); } @@ -142,6 +143,11 @@ public class TbHttpClient { } } + private SslContext initSslContext() throws SSLException { + return this.config.getCredentials().initSslContext() + .orElse(SslContextBuilder.forClient().build()); + } + private void checkSystemProxyProperties() throws TbNodeException { boolean useHttpProxy = !StringUtils.isEmpty(System.getProperty("http.proxyHost")) && !StringUtils.isEmpty(System.getProperty("http.proxyPort")); boolean useHttpsProxy = !StringUtils.isEmpty(System.getProperty("https.proxyHost")) && !StringUtils.isEmpty(System.getProperty("https.proxyPort")); @@ -226,6 +232,7 @@ public class TbHttpClient { private HttpHeaders prepareHeaders(TbMsgMetaData metaData) { HttpHeaders headers = new HttpHeaders(); config.getHeaders().forEach((k, v) -> headers.add(TbNodeUtils.processPattern(k, metaData), TbNodeUtils.processPattern(v, metaData))); + config.getCredentials().getBasicAuthHeaderValue().ifPresent(v -> headers.add("Authorization", v)); return headers; } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbRestApiCallNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbRestApiCallNodeConfiguration.java index bcc6ad60c8..961e2602bc 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbRestApiCallNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbRestApiCallNodeConfiguration.java @@ -18,6 +18,8 @@ package org.thingsboard.rule.engine.rest; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; import org.thingsboard.rule.engine.api.NodeConfiguration; +import org.thingsboard.rule.engine.rest.credentials.HttpAnonymousCredentials; +import org.thingsboard.rule.engine.rest.credentials.HttpClientCredentials; import java.util.Collections; import java.util.Map; @@ -42,6 +44,7 @@ public class TbRestApiCallNodeConfiguration implements NodeConfiguration getBasicAuthHeaderValue() { + String authString = getUsername() + ":" + getPassword(); + String encodedAuthString = new String(Base64.encodeBase64(authString.getBytes(StandardCharsets.UTF_8))); + return Optional.of("Basic " + encodedAuthString); + } +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpCertPemCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpCertPemCredentials.java new file mode 100644 index 0000000000..3aac4a596f --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpCertPemCredentials.java @@ -0,0 +1,21 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.rest.credentials; + +import org.thingsboard.rule.engine.credentials.CertPemCredentials; + +public class HttpCertPemCredentials extends CertPemCredentials implements HttpClientCredentials { +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpClientCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpClientCredentials.java new file mode 100644 index 0000000000..0f81f6ad8b --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpClientCredentials.java @@ -0,0 +1,38 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.rest.credentials; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import io.netty.handler.ssl.SslContext; + +import java.util.Optional; + +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") +@JsonSubTypes({ + @JsonSubTypes.Type(value = HttpAnonymousCredentials.class, name = "anonymous"), + @JsonSubTypes.Type(value = HttpBasicCredentials.class, name = "basic"), + @JsonSubTypes.Type(value = HttpCertPemCredentials.class, name = "cert.PEM")}) +public interface HttpClientCredentials { + default Optional initSslContext() { + return Optional.empty(); + } + + default Optional getBasicAuthHeaderValue() { + return Optional.empty(); + } +} + diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/credentials/HttpBasicCredentialsTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/credentials/HttpBasicCredentialsTest.java new file mode 100644 index 0000000000..abdbd76cc4 --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/credentials/HttpBasicCredentialsTest.java @@ -0,0 +1,34 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.rest.credentials; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.Optional; + +public class HttpBasicCredentialsTest { + @Test + public void getBasicAuthHeaderValueTest() { + HttpBasicCredentials credentials = new HttpBasicCredentials(); + credentials.setUsername("testUser"); + credentials.setPassword("testPwd"); + Optional actualHeaderValue = credentials.getBasicAuthHeaderValue(); + Optional expectedHeaderValue = Optional.of("Basic dGVzdFVzZXI6dGVzdFB3ZA=="); + + Assert.assertEquals(expectedHeaderValue, actualHeaderValue); + } +} From de7e25f7316308ab3d3d0219970b68b12df7097a Mon Sep 17 00:00:00 2001 From: Viacheslav Kukhtyn Date: Sat, 9 Jan 2021 17:52:27 +0200 Subject: [PATCH 023/249] CA cert or client cert-key pair could be optional --- .../engine/credentials/CertPemCredentials.java | 14 ++++++++------ .../thingsboard/rule/engine/rest/TbHttpClient.java | 8 +------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CertPemCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CertPemCredentials.java index 055741584c..5a7b3139f0 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CertPemCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CertPemCredentials.java @@ -16,7 +16,6 @@ package org.thingsboard.rule.engine.credentials; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import io.netty.handler.ssl.ClientAuth; import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContextBuilder; import lombok.Data; @@ -66,11 +65,14 @@ public class CertPemCredentials { public Optional initSslContext() { try { Security.addProvider(new BouncyCastleProvider()); - return Optional.of(SslContextBuilder.forClient() - .keyManager(createAndInitKeyManagerFactory()) - .trustManager(createAndInitTrustManagerFactory()) - .clientAuth(ClientAuth.REQUIRE) - .build()); + SslContextBuilder builder = SslContextBuilder.forClient(); + if (StringUtils.hasLength(caCert)) { + builder.trustManager(createAndInitTrustManagerFactory()); + } + if (StringUtils.hasLength(cert) && StringUtils.hasLength(privateKey)) { + builder.keyManager(createAndInitKeyManagerFactory()); + } + return Optional.of(builder.build()); } catch (Exception e) { log.error("[{}:{}] Creating TLS factory failed!", caCert, cert, e); throw new RuntimeException("Creating TLS factory failed!", e); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java index 08cda8e322..226c74f39f 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java @@ -17,7 +17,6 @@ package org.thingsboard.rule.engine.rest; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContextBuilder; import lombok.Data; import lombok.extern.slf4j.Slf4j; @@ -134,7 +133,7 @@ public class TbHttpClient { } else { this.eventLoopGroup = new NioEventLoopGroup(); Netty4ClientHttpRequestFactory nettyFactory = new Netty4ClientHttpRequestFactory(this.eventLoopGroup); - nettyFactory.setSslContext(initSslContext()); + nettyFactory.setSslContext(config.getCredentials().initSslContext().orElse(SslContextBuilder.forClient().build())); nettyFactory.setReadTimeout(config.getReadTimeoutMs()); httpClient = new AsyncRestTemplate(nettyFactory); } @@ -143,11 +142,6 @@ public class TbHttpClient { } } - private SslContext initSslContext() throws SSLException { - return this.config.getCredentials().initSslContext() - .orElse(SslContextBuilder.forClient().build()); - } - private void checkSystemProxyProperties() throws TbNodeException { boolean useHttpProxy = !StringUtils.isEmpty(System.getProperty("http.proxyHost")) && !StringUtils.isEmpty(System.getProperty("http.proxyPort")); boolean useHttpsProxy = !StringUtils.isEmpty(System.getProperty("https.proxyHost")) && !StringUtils.isEmpty(System.getProperty("https.proxyPort")); From 17700fe186bed6f24e90d3603804f48208312c11 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Mon, 11 Jan 2021 19:26:12 +0200 Subject: [PATCH 024/249] Lwm2m: backEnd: refactoring after update dependencies: 2.6.0 1.3.0 1.3.0 1.3.0 --- .../service/lwm2m/LwM2MModelsRepository.java | 21 ++-- .../src/main/resources/thingsboard.yml | 50 +++++---- common/transport/lwm2m/pom.xml | 8 ++ ...TransportBootstrapServerConfiguration.java | 47 +++++--- ...2MTransportBootstrapServerInitializer.java | 37 ++++--- .../LwM2mDefaultBootstrapSessionManager.java | 1 - .../lwm2m/server/LwM2MTransportHandler.java | 4 +- .../lwm2m/server/LwM2MTransportRequest.java | 7 +- .../LwM2MTransportServerConfiguration.java | 63 ++++++----- .../LwM2MTransportServerInitializer.java | 67 +++++++----- .../lwm2m/server/LwM2MTransportService.java | 2 +- .../server/LwM2MTransportServiceImpl.java | 83 +++++++++------ .../lwm2m/server/LwM2mServerListener.java | 4 +- .../lwm2m/server/client/LwM2MClient.java | 6 +- .../lwm2m/server/client/ResourceValue.java | 2 +- .../lwm2m/LwM2MTransportConfigBootstrap.java | 48 ++++++--- .../lwm2m/LwM2MTransportConfigServer.java | 100 ++++++++++++------ pom.xml | 13 +-- transport/lwm2m/pom.xml | 60 +++++++---- .../src/main/resources/tb-lwm2m-transport.yml | 51 +++++---- ui-ngx/angular.json | 5 +- ...m2m-object-add-instances-list.component.ts | 2 +- .../lwm2m-object-add-instances.component.ts | 3 +- ...serve-attr-telemetry-resource.component.ts | 4 +- .../lwm2m-observe-attr-telemetry.component.ts | 1 - .../device/lwm2m/profile-config.models.ts | 33 +----- 26 files changed, 417 insertions(+), 305 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MModelsRepository.java b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MModelsRepository.java index e314cd8f51..cea898e7a1 100644 --- a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MModelsRepository.java +++ b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MModelsRepository.java @@ -150,53 +150,54 @@ public class LwM2MModelsRepository { */ private ServerSecurityConfig getBootstrapServer(boolean bootstrapServerIs, LwM2MSecurityMode mode) { ServerSecurityConfig bsServ = new ServerSecurityConfig(); + bsServ.setBootstrapServerIs(bootstrapServerIs); if (bootstrapServerIs) { + bsServ.setServerId(contextBootStrap.getBootstrapServerId()); switch (mode) { case NO_SEC: bsServ.setHost(contextBootStrap.getBootstrapHost()); - bsServ.setPort(contextBootStrap.getBootstrapPort()); + bsServ.setPort(contextBootStrap.getBootstrapPortNoSecPsk()); bsServ.setServerPublicKey(""); break; case PSK: bsServ.setHost(contextBootStrap.getBootstrapSecureHost()); - bsServ.setPort(contextBootStrap.getBootstrapSecurePort()); + bsServ.setPort(contextBootStrap.getBootstrapSecurePortPsk()); bsServ.setServerPublicKey(""); break; case RPK: bsServ.setHost(contextBootStrap.getBootstrapSecureHost()); - bsServ.setPort(contextBootStrap.getBootstrapSecurePort()); + bsServ.setPort(contextBootStrap.getBootstrapSecurePortRpk()); bsServ.setServerPublicKey(getRPKPublicKey(this.contextBootStrap.getBootstrapPublicX(), this.contextBootStrap.getBootstrapPublicY())); break; case X509: bsServ.setHost(contextBootStrap.getBootstrapSecureHost()); - bsServ.setPort(contextBootStrap.getBootstrapSecurePortCert()); + bsServ.setPort(contextBootStrap.getBootstrapSecurePortX509()); bsServ.setServerPublicKey(getServerPublicKeyX509(contextBootStrap.getBootstrapAlias())); break; default: break; } } else { - bsServ.setBootstrapServerIs(bootstrapServerIs); - bsServ.setServerId(123); + bsServ.setServerId(contextServer.getServerId()); switch (mode) { case NO_SEC: bsServ.setHost(contextServer.getServerHost()); - bsServ.setPort(contextServer.getServerPort()); + bsServ.setPort(contextServer.getServerPortNoSecPsk()); bsServ.setServerPublicKey(""); break; case PSK: bsServ.setHost(contextServer.getServerSecureHost()); - bsServ.setPort(contextServer.getServerSecurePort()); + bsServ.setPort(contextServer.getServerPortPsk()); bsServ.setServerPublicKey(""); break; case RPK: bsServ.setHost(contextServer.getServerSecureHost()); - bsServ.setPort(contextServer.getServerSecurePort()); + bsServ.setPort(contextServer.getServerPortRpk()); bsServ.setServerPublicKey(getRPKPublicKey(this.contextServer.getServerPublicX(), this.contextServer.getServerPublicY())); break; case X509: bsServ.setHost(contextServer.getServerSecureHost()); - bsServ.setPort(contextServer.getServerSecurePortCert()); + bsServ.setPort(contextServer.getServerPortX509()); bsServ.setServerPublicKey(getServerPublicKeyX509(contextServer.getServerAlias())); break; default: diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 065a0a4cb0..8c2d7e1702 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -575,7 +575,13 @@ transport: timeout: "${LWM2M_TIMEOUT:120000}" # model_path_file: "${LWM2M_MODEL_PATH_FILE:./common/transport/lwm2m/src/main/resources/models/}" model_path_file: "${LWM2M_MODEL_PATH_FILE:}" - support_deprecated_ciphers_enable: "${LWM2M_SUPPORT_DEPRECATED_CIPHERS_ENABLED:true}" + recommended_ciphers: "${LWM2M_RECOMMENDED_CIPHERS:false}" + recommended_supported_groups: "${LWM2M_RECOMMENDED_SUPPORTED_GROUPS:false}" + request_pool_size: "${LWM2M_REQUEST_POOL_SIZE:100}" + request_error_pool_size: "${LWM2M_REQUEST_ERROR_POOL_SIZE:10}" + registered_pool_size: "${LWM2M_REGISTERED_POOL_SIZE:10}" + update_registered_pool_size: "${LWM2M_UPDATE_REGISTERED_POOL_SIZE:10}" + un_registered_pool_size: "${LWM2M_UN_REGISTERED_POOL_SIZE:10}" secure: # Only Certificate_x509: # To get helps about files format and how to generate it, see: https://github.com/eclipse/leshan/wiki/Credential-files-format @@ -588,24 +594,19 @@ transport: root_alias: "${LWM2M_SERVER_ROOT_CA:rootca}" enable_gen_psk_rpk: "${ENABLE_GEN_PSK_RPK:true}" server: + id: "${LWM2M_SERVER_ID:123}" bind_address: "${LWM2M_BIND_ADDRESS:0.0.0.0}" - bind_port: "${LWM2M_BIND_PORT:5685}" - bind_port_cert: "${LWM2M_BIND_PORT_CERT:5687}" + bind_port_no_sec_psk: "${LWM2M_BIND_PORT_NO_SEC_PSK:5685}" + bind_port_no_sec_rpk: "${LWM2M_BIND_PORT_NO_SEC_RPK:5687}" + bind_port_no_sec_x509: "${LWM2M_BIND_PORT_NO_SEC_X509:5689}" secure: - start_all: "${START_SERVER_ALL:true}" - #leshan.core (V1_1) - #DTLS security modes: - #0: Pre-Shared Key mode - #1: Raw Public Key mode - #2: Certificate mode X509 - #3: NoSec mode * - #OMA-TS-LightweightM2M_Core-V1_1_1-20190617-A (add) - #4: Certificate mode X509 with EST - # If only startAll == false - dtls_mode: "${LWM2M_SECURITY_MODE:1}" bind_address: "${LWM2M_BIND_ADDRESS:0.0.0.0}" - bind_port: "${LWM2M_BIND_PORT_SEC:5686}" - bind_port_cert: "${LWM2M_BIND_PORT_SEC_CERT:5688}" + start_psk: "${START_SERVER_PSK:true}" + start_rpk: "${START_SERVER_RPK:true}" + start_x509: "${START_SERVER_X509:true}" + bind_port_psk: "${LWM2M_BIND_PORT_SEC_PSK:5686}" + bind_port_rpk: "${LWM2M_BIND_PORT_SEC_RPK:5688}" + bind_port_x509: "${LWM2M_BIND_PORT_SEC_X509:5690}" # Only RPK: Public & Private Key # create_rpk: "${CREATE_RPK:}" public_x: "${LWM2M_SERVER_PUBLIC_X:405354ea8893471d9296afbc8b020a5c6201b0bb25812a53b849d4480fa5f069}" @@ -615,16 +616,19 @@ transport: alias: "${LWM2M_KEYSTORE_ALIAS_SERVER:server}" bootstrap: enable: "${BOOTSTRAP:true}" + id: "${LWM2M_SERVER_ID:111}" bind_address: "${LWM2M_BIND_ADDRESS_BS:0.0.0.0}" - bind_port: "${LWM2M_BIND_PORT_BS:5689}" - bind_port_cert: "${LWM2M_BIND_PORT_SER_BS:5691}" + bind_port_no_sec_psk: "${LWM2M_BIND_PORT_NO_SEC_BS:5691}" + bind_port_no_sec_rpk: "${LWM2M_BIND_PORT_NO_SEC_BS:5693}" + bind_port_no_sec_x509: "${LWM2M_BIND_PORT_NO_SEC_BS:5695}" secure: - start_all: "${START_BOOTSTRAP_ALL:true}" - # If only startAll == false - dtls_mode: "${LWM2M_SECURITY_MODE_BS:1}" bind_address: "${LWM2M_BIND_ADDRESS_BS:0.0.0.0}" - bind_port: "${LWM2M_BIND_PORT_SEC_BS:5690}" - bind_port_cert: "${LWM2M_BIND_PORT_SEC_CERT_BS:5692}" + start_psk: "${START_SERVER_PSK_BS:true}" + start_rpk: "${START_SERVER_RPK_BS:true}" + start_x509: "${START_SERVER_X509_BS:true}" + bind_port_psk: "${LWM2M_BIND_PORT_SEC_PSK_BS:5692}" + bind_port_rpk: "${LWM2M_BIND_PORT_SER_RPK_BS:5694}" + bind_port_x509: "${LWM2M_BIND_PORT_SEC_X509_BS:5696}" # Only RPK: Public & Private Key public_x: "${LWM2M_SERVER_PUBLIC_X_BS:993ef2b698c6a9c0c1d8be78b13a9383c0854c7c7c7a504d289b403794648183}" public_y: "${LWM2M_SERVER_PUBLIC_Y_BS:267412d5fc4e5ceb2257cb7fd7f76ebdac2fa9aa100afb162e990074cc0bfaa2}" diff --git a/common/transport/lwm2m/pom.xml b/common/transport/lwm2m/pom.xml index d23f8dbc5d..44a764be2b 100644 --- a/common/transport/lwm2m/pom.xml +++ b/common/transport/lwm2m/pom.xml @@ -99,6 +99,14 @@ test-jar test + + org.eclipse.californium + californium-core + + + + + org.eclipse.californium element-connector diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerConfiguration.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerConfiguration.java index 588de9bba2..17999326d7 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerConfiguration.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerConfiguration.java @@ -52,7 +52,9 @@ import java.security.spec.ECPublicKeySpec; import java.security.spec.KeySpec; import java.util.Arrays; +import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256; import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.NO_SEC; +import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.PSK; import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.RPK; import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.X509; import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.getCoapConfig; @@ -76,27 +78,32 @@ public class LwM2MTransportBootstrapServerConfiguration { @Autowired private LwM2MInMemoryBootstrapConfigStore lwM2MInMemoryBootstrapConfigStore; - @Primary - @Bean(name = "leshanBootstrapCert") - public LeshanBootstrapServer getLeshanBootstrapServerCert() { - log.info("Prepare and start BootstrapServerCert... PostConstruct"); - return getLeshanBootstrapServer(this.contextBs.getCtxBootStrap().getBootstrapPortCert(), this.contextBs.getCtxBootStrap().getBootstrapSecurePortCert(), X509); + @Bean(name = "leshanBootstrapX509") + public LeshanBootstrapServer getLeshanBootstrapServerX509() { + log.info("Prepare and start BootstrapServerX509... PostConstruct"); + return getLeshanBootstrapServer(this.contextBs.getCtxBootStrap().getBootstrapPortNoSecX509(), this.contextBs.getCtxBootStrap().getBootstrapSecurePortX509(), X509); + } + + @Bean(name = "leshanBootstrapPsk") + public LeshanBootstrapServer getLeshanBootstrapServerPsk() { + log.info("Prepare and start BootstrapServerRsk... PostConstruct"); + return getLeshanBootstrapServer(this.contextBs.getCtxBootStrap().getBootstrapPortNoSecPsk(), this.contextBs.getCtxBootStrap().getBootstrapSecurePortPsk(), PSK); } - @Bean(name = "leshanBootstrapRPK") - public LeshanBootstrapServer getLeshanBootstrapServerRPK() { - log.info("Prepare and start BootstrapServerRPK... PostConstruct"); - return getLeshanBootstrapServer(this.contextBs.getCtxBootStrap().getBootstrapPort(), this.contextBs.getCtxBootStrap().getBootstrapSecurePort(), RPK); + @Bean(name = "leshanBootstrapRpk") + public LeshanBootstrapServer getLeshanBootstrapServerRpk() { + log.info("Prepare and start BootstrapServerRpk... PostConstruct"); + return getLeshanBootstrapServer(this.contextBs.getCtxBootStrap().getBootstrapPortNoSecRpk(), this.contextBs.getCtxBootStrap().getBootstrapSecurePortRpk(), RPK); } - public LeshanBootstrapServer getLeshanBootstrapServer(Integer bootstrapPort, Integer bootstrapSecurePort, LwM2MSecurityMode dtlsMode) { + public LeshanBootstrapServer getLeshanBootstrapServer(Integer bootstrapPortNoSec, Integer bootstrapSecurePort, LwM2MSecurityMode dtlsMode) { LeshanBootstrapServerBuilder builder = new LeshanBootstrapServerBuilder(); - builder.setLocalAddress(this.contextBs.getCtxBootStrap().getBootstrapHost(), bootstrapPort); + builder.setLocalAddress(this.contextBs.getCtxBootStrap().getBootstrapHost(), bootstrapPortNoSec); builder.setLocalSecureAddress(this.contextBs.getCtxBootStrap().getBootstrapSecureHost(), bootstrapSecurePort); /** Create CoAP Config */ - builder.setCoapConfig(getCoapConfig ()); + builder.setCoapConfig(getCoapConfig (bootstrapPortNoSec, bootstrapSecurePort)); /** ConfigStore */ builder.setConfigStore(lwM2MInMemoryBootstrapConfigStore); @@ -107,13 +114,22 @@ public class LwM2MTransportBootstrapServerConfiguration { /** Define model provider (Create Models )*/ builder.setModel(new StaticModel(contextS.getCtxServer().getModelsValue())); + /** Create credentials */ + LwM2MSetSecurityStoreBootstrap(builder, dtlsMode); + /** Create and Set DTLS Config */ DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(); - dtlsConfig.setRecommendedCipherSuitesOnly(contextS.getCtxServer().isSupportDeprecatedCiphersEnable()); + if (dtlsMode==PSK) { + dtlsConfig.setRecommendedCipherSuitesOnly(this.contextS.getCtxServer().isRecommendedCiphers()); + dtlsConfig.setRecommendedSupportedGroupsOnly(this.contextS.getCtxServer().isRecommendedSupportedGroups()); + dtlsConfig.setSupportedCipherSuites(TLS_PSK_WITH_AES_128_CBC_SHA256); + } + else { + dtlsConfig.setRecommendedCipherSuitesOnly(this.contextS.getCtxServer().isRecommendedCiphers()); +// dtlsConfig.setRecommendedSupportedGroupsOnly(false); + } builder.setDtlsConfig(dtlsConfig); - /** Create credentials */ - LwM2MSetSecurityStoreBootstrap(builder, dtlsMode); BootstrapSessionManager sessionManager = new LwM2mDefaultBootstrapSessionManager(lwM2MBootstrapSecurityStore); builder.setSessionManager(sessionManager); @@ -133,6 +149,7 @@ public class LwM2MTransportBootstrapServerConfiguration { break; /** Use PSK/RPK */ case PSK: + break; case RPK: setRPK(builder); break; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerInitializer.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerInitializer.java index cb927a76b9..6ffa3e8bdf 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerInitializer.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerInitializer.java @@ -14,13 +14,13 @@ * limitations under the License. */ package org.thingsboard.server.transport.lwm2m.bootstrap; + import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Service; -import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @@ -31,40 +31,39 @@ import javax.annotation.PreDestroy; public class LwM2MTransportBootstrapServerInitializer { @Autowired - @Qualifier("leshanBootstrapCert") + @Qualifier("leshanBootstrapX509") private LeshanBootstrapServer lhBServerCert; @Autowired - @Qualifier("leshanBootstrapRPK") - private LeshanBootstrapServer lhBServerRPK; + @Qualifier("leshanBootstrapPsk") + private LeshanBootstrapServer lhBServerPsk; + + @Autowired + @Qualifier("leshanBootstrapRpk") + private LeshanBootstrapServer lhBServerRpk; @Autowired private LwM2MTransportContextBootstrap contextBS; @PostConstruct public void init() { - if (this.contextBS.getCtxBootStrap().isBootstrapStartAll()) { - this.lhBServerCert.start(); - this.lhBServerRPK.start(); + if (this.contextBS.getCtxBootStrap().getBootstrapStartPsk()) { + this.lhBServerPsk.start(); } - else { - if (this.contextBS.getCtxBootStrap().getBootStrapDtlsMode() == LwM2MSecurityMode.X509.code) { - this.lhBServerCert.start(); - } - else { - this.lhBServerRPK.start(); - } + if (this.contextBS.getCtxBootStrap().getBootstrapStartRpk()) { + this.lhBServerRpk.start(); + } + if (this.contextBS.getCtxBootStrap().getBootstrapStartX509()) { + this.lhBServerCert.start(); } } @PreDestroy public void shutdown() throws InterruptedException { log.info("Stopping LwM2M transport Bootstrap Server!"); - try { - lhBServerCert.destroy(); - lhBServerRPK.destroy(); - } finally { - } + lhBServerPsk.destroy(); + lhBServerRpk.destroy(); + lhBServerCert.destroy(); log.info("LwM2M transport Bootstrap Server stopped!"); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java index db8a520266..6608635ee0 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java @@ -49,7 +49,6 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession this.securityChecker = securityChecker; } - @Override public BootstrapSession begin(String endpoint, Identity clientIdentity) { boolean authorized; if (bsSecurityStore != null) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportHandler.java index 76cc2a8015..dbca7a8f5b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportHandler.java @@ -141,7 +141,7 @@ public class LwM2MTransportHandler { // } // } - public static NetworkConfig getCoapConfig() { + public static NetworkConfig getCoapConfig(Integer serverPortNoSec, Integer serverSecurePort) { NetworkConfig coapConfig; File configFile = new File(NetworkConfig.DEFAULT_FILE_NAME); if (configFile.isFile()) { @@ -151,6 +151,8 @@ public class LwM2MTransportHandler { coapConfig = LeshanServerBuilder.createDefaultNetworkConfig(); coapConfig.store(configFile); } + coapConfig.setString("COAP_PORT", Integer.toString(serverPortNoSec)); + coapConfig.setString("COAP_SECURE_PORT", Integer.toString(serverSecurePort)); return coapConfig; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java index de03e25767..d5884b5b86 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java @@ -88,12 +88,15 @@ public class LwM2MTransportRequest { @Autowired LwM2MTransportServiceImpl service; + @Autowired + public LwM2MTransportContextServer context; + @PostConstruct public void init() { this.converter = LwM2mValueConverterImpl.getInstance(); - executorResponse = Executors.newFixedThreadPool(10, + executorResponse = Executors.newFixedThreadPool(this.context.getCtxServer().getRequestPoolSize(), new NamedThreadFactory(String.format("LwM2M %s channel response", RESPONSE_CHANNEL))); - executorResponseError = Executors.newFixedThreadPool(10, + executorResponseError = Executors.newFixedThreadPool(this.context.getCtxServer().getRequestErrorPoolSize(), new NamedThreadFactory(String.format("LwM2M %s channel response Error", RESPONSE_CHANNEL))); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerConfiguration.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerConfiguration.java index c809491803..71fc65967b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerConfiguration.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerConfiguration.java @@ -62,6 +62,8 @@ import java.security.spec.ECPublicKeySpec; import java.security.spec.KeySpec; import java.util.Arrays; +import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256; +import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.PSK; import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.RPK; import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.X509; import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.getCoapConfig; @@ -83,24 +85,27 @@ public class LwM2MTransportServerConfiguration { private LwM2mInMemorySecurityStore lwM2mInMemorySecurityStore; @Primary - @Bean(name = "LeshanServerCert") - public LeshanServer getLeshanServerCert() { - log.info("Starting LwM2M transport ServerCert... PostConstruct"); - LeshanServer leshanServerCert = getLeshanServer(this.context.getCtxServer().getServerPortCert(), this.context.getCtxServer().getServerSecurePortCert(), X509); - - return leshanServerCert; + @Bean(name = "leshanServerX509") + public LeshanServer getLeshanServerX509() { + log.info("Starting LwM2M transport ServerX509... PostConstruct"); + return getLeshanServer(this.context.getCtxServer().getServerPortNoSecX509(), this.context.getCtxServer().getServerPortX509(), X509); } - @Bean(name = "LeshanServerNoSecPskRpk") - public LeshanServer getLeshanServerNoSecPskRpk() { - log.info("Starting LwM2M transport ServerNoSecPskRpk... PostConstruct"); - return getLeshanServer(this.context.getCtxServer().getServerPort(), this.context.getCtxServer().getServerSecurePort(), RPK); + @Bean(name = "leshanServerPsk") + public LeshanServer getLeshanServerPsk() { + log.info("Starting LwM2M transport ServerPsk... PostConstruct"); + return getLeshanServer(this.context.getCtxServer().getServerPortNoSecPsk(), this.context.getCtxServer().getServerPortPsk(), PSK); } - private LeshanServer getLeshanServer(Integer serverPort, Integer serverSecurePort, LwM2MSecurityMode dtlsMode) { + @Bean(name = "leshanServerRpk") + public LeshanServer getLeshanServerRpk() { + log.info("Starting LwM2M transport ServerRpk... PostConstruct"); + return getLeshanServer(this.context.getCtxServer().getServerPortNoSecRpk(), this.context.getCtxServer().getServerPortRpk(), RPK); + } + private LeshanServer getLeshanServer(Integer serverPortNoSec, Integer serverSecurePort, LwM2MSecurityMode dtlsMode) { LeshanServerBuilder builder = new LeshanServerBuilder(); - builder.setLocalAddress(this.context.getCtxServer().getServerHost(), serverPort); + builder.setLocalAddress(this.context.getCtxServer().getServerHost(), serverPortNoSec); builder.setLocalSecureAddress(this.context.getCtxServer().getServerSecureHost(), serverSecurePort); builder.setEncoder(new DefaultLwM2mNodeEncoder()); LwM2mNodeDecoder decoder = new DefaultLwM2mNodeDecoder(); @@ -108,43 +113,47 @@ public class LwM2MTransportServerConfiguration { builder.setEncoder(new DefaultLwM2mNodeEncoder(LwM2mValueConverterImpl.getInstance())); /** Create CoAP Config */ - builder.setCoapConfig(getCoapConfig()); + builder.setCoapConfig(getCoapConfig(serverPortNoSec, serverSecurePort)); /** Define model provider (Create Models )*/ LwM2mModelProvider modelProvider = new VersionedModelProvider(this.context.getCtxServer().getModelsValue()); builder.setObjectModelProvider(modelProvider); + /** Create DTLS security mode + * There can be only one DTLS security mode + */ + this.LwM2MSetSecurityStoreServer(builder, dtlsMode); + /** Create DTLS Config */ DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(); - dtlsConfig.setRecommendedCipherSuitesOnly(this.context.getCtxServer().isSupportDeprecatedCiphersEnable()); + if (dtlsMode==PSK) { + dtlsConfig.setRecommendedCipherSuitesOnly(this.context.getCtxServer().isRecommendedCiphers()); + dtlsConfig.setRecommendedSupportedGroupsOnly(this.context.getCtxServer().isRecommendedSupportedGroups()); + dtlsConfig.setSupportedCipherSuites(TLS_PSK_WITH_AES_128_CBC_SHA256); + } + else { + dtlsConfig.setRecommendedSupportedGroupsOnly(!this.context.getCtxServer().isRecommendedSupportedGroups()); + dtlsConfig.setRecommendedCipherSuitesOnly(!this.context.getCtxServer().isRecommendedCiphers()); + } /** Set DTLS Config */ builder.setDtlsConfig(dtlsConfig); /** Use a magic converter to support bad type send by the UI. */ builder.setEncoder(new DefaultLwM2mNodeEncoder(LwM2mValueConverterImpl.getInstance())); - /** Create DTLS security mode - * There can be only one DTLS security mode - */ - this.LwM2MSetSecurityStoreServer(builder, dtlsMode); /** Create LWM2M server */ return builder.build(); } - private void LwM2MSetSecurityStoreServer(LeshanServerBuilder builder, LwM2MSecurityMode dtlsMode) { + private void LwM2MSetSecurityStoreServer(LeshanServerBuilder builder, LwM2MSecurityMode dtlsMode) { /** Set securityStore with new registrationStore */ EditableSecurityStore securityStore = lwM2mInMemorySecurityStore; - switch (dtlsMode) { /** Use PSK only */ case PSK: generatePSK_RPK(); - if (this.privateKey != null && this.privateKey.getEncoded().length > 0) { - builder.setPrivateKey(this.privateKey); - builder.setPublicKey(null); - infoParamsPSK(); - } + infoParamsPSK(); break; /** Use RPK only */ case RPK: @@ -233,7 +242,7 @@ public class LwM2MTransportServerConfiguration { private void infoParamsPSK() { log.info("\nServer uses PSK -> private key : \n security key : [{}] \n serverSecureURI : [{}]", Hex.encodeHexString(this.privateKey.getEncoded()), - this.context.getCtxServer().getServerSecureHost() + ":" + Integer.toString(this.context.getCtxServer().getServerSecurePort())); + this.context.getCtxServer().getServerSecureHost() + ":" + Integer.toString(this.context.getCtxServer().getServerPortPsk())); } private void infoParamsRPK() { @@ -298,6 +307,4 @@ public class LwM2MTransportServerConfiguration { log.error("[{}] Unable to load KeyStore files server", ex.getMessage()); } } - - } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerInitializer.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerInitializer.java index da4cdbf634..6fbcb78f9c 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerInitializer.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerInitializer.java @@ -22,7 +22,6 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Component; import org.thingsboard.server.transport.lwm2m.secure.LWM2MGenerationPSkRPkECC; -import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @@ -37,12 +36,16 @@ public class LwM2MTransportServerInitializer { private LwM2MTransportServiceImpl service; @Autowired - @Qualifier("LeshanServerCert") - private LeshanServer lhServerCert; + @Qualifier("leshanServerX509") + private LeshanServer lhServerX509; @Autowired - @Qualifier("LeshanServerNoSecPskRpk") - private LeshanServer lhServerNoSecPskRpk; + @Qualifier("leshanServerPsk") + private LeshanServer lhServerPsk; + + @Autowired + @Qualifier("leshanServerRpk") + private LeshanServer lhServerRpk; @Autowired private LwM2MTransportContextServer context; @@ -50,39 +53,47 @@ public class LwM2MTransportServerInitializer { @PostConstruct public void init() { if (this.context.getCtxServer().getEnableGenPskRpk()) new LWM2MGenerationPSkRPkECC(); - if (this.context.getCtxServer().isServerStartAll()) { - this.startLhServerCert(); - this.startLhServerNoSecPskRpk(); - } else { - if (this.context.getCtxServer().getServerDtlsMode() == LwM2MSecurityMode.X509.code) { - this.startLhServerCert(); - } else { - this.startLhServerNoSecPskRpk(); - } + if (this.context.getCtxServer().isServerStartPsk()) { + this.startLhServerPsk(); + } + if (this.context.getCtxServer().isServerStartRpk()) { + this.startLhServerRpk(); } + if (this.context.getCtxServer().isServerStartX509()) { + this.startLhServerX509(); + } + } + + private void startLhServerPsk() { + this.lhServerPsk.start(); + LwM2mServerListener lhServerPskListener = new LwM2mServerListener(this.lhServerPsk, service); + this.lhServerPsk.getRegistrationService().addListener(lhServerPskListener.registrationListener); + this.lhServerPsk.getPresenceService().addListener(lhServerPskListener.presenceListener); + this.lhServerPsk.getObservationService().addListener(lhServerPskListener.observationListener); } - private void startLhServerCert() { - this.lhServerCert.start(); - LwM2mServerListener lhServerCertListener = new LwM2mServerListener(this.lhServerCert, service); - this.lhServerCert.getRegistrationService().addListener(lhServerCertListener.registrationListener); - this.lhServerCert.getPresenceService().addListener(lhServerCertListener.presenceListener); - this.lhServerCert.getObservationService().addListener(lhServerCertListener.observationListener); + private void startLhServerRpk() { + this.lhServerRpk.start(); + LwM2mServerListener lhServerRpkListener = new LwM2mServerListener(this.lhServerRpk, service); + this.lhServerRpk.getRegistrationService().addListener(lhServerRpkListener.registrationListener); + this.lhServerRpk.getPresenceService().addListener(lhServerRpkListener.presenceListener); + this.lhServerRpk.getObservationService().addListener(lhServerRpkListener.observationListener); } - private void startLhServerNoSecPskRpk() { - this.lhServerNoSecPskRpk.start(); - LwM2mServerListener lhServerNoSecPskRpkListener = new LwM2mServerListener(this.lhServerNoSecPskRpk, service); - this.lhServerNoSecPskRpk.getRegistrationService().addListener(lhServerNoSecPskRpkListener.registrationListener); - this.lhServerNoSecPskRpk.getPresenceService().addListener(lhServerNoSecPskRpkListener.presenceListener); - this.lhServerNoSecPskRpk.getObservationService().addListener(lhServerNoSecPskRpkListener.observationListener); + private void startLhServerX509() { + this.lhServerX509.start(); + LwM2mServerListener lhServerCertListener = new LwM2mServerListener(this.lhServerX509, service); + this.lhServerX509.getRegistrationService().addListener(lhServerCertListener.registrationListener); + this.lhServerX509.getPresenceService().addListener(lhServerCertListener.presenceListener); + this.lhServerX509.getObservationService().addListener(lhServerCertListener.observationListener); } @PreDestroy public void shutdown() { log.info("Stopping LwM2M transport Server!"); - lhServerCert.destroy(); - lhServerNoSecPskRpk.destroy(); + lhServerPsk.destroy(); + lhServerRpk.destroy(); + lhServerX509.destroy(); log.info("LwM2M transport Server stopped!"); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java index a9fcbcb669..3b21e7003f 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java @@ -32,7 +32,7 @@ public interface LwM2MTransportService { void updatedReg(LeshanServer lwServer, Registration registration); - void unReg(Registration registration, Collection observations); + void unReg(LeshanServer lwServer, Registration registration, Collection observations); void onSleepingDev(Registration registration); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServiceImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServiceImpl.java index c4575c1a8f..072c7bc402 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServiceImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServiceImpl.java @@ -20,7 +20,6 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import lombok.extern.slf4j.Slf4j; -import org.eclipse.leshan.core.Link; import org.eclipse.leshan.core.model.ResourceModel; import org.eclipse.leshan.core.node.LwM2mMultipleResource; import org.eclipse.leshan.core.node.LwM2mObject; @@ -57,6 +56,7 @@ import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import javax.annotation.PostConstruct; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.LinkedHashSet; @@ -120,11 +120,11 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { @PostConstruct public void init() { this.context.getScheduler().scheduleAtFixedRate(this::checkInactivityAndReportActivity, new Random().nextInt((int) context.getCtxServer().getSessionReportTimeout()), context.getCtxServer().getSessionReportTimeout(), TimeUnit.MILLISECONDS); - this.executorRegistered = Executors.newFixedThreadPool(10, + this.executorRegistered = Executors.newFixedThreadPool(this.context.getCtxServer().getRegisteredPoolSize(), new NamedThreadFactory(String.format("LwM2M %s channel registered", SERVICE_CHANNEL))); - this.executorUpdateRegistered = Executors.newFixedThreadPool(10, + this.executorUpdateRegistered = Executors.newFixedThreadPool(this.context.getCtxServer().getUpdateRegisteredPoolSize(), new NamedThreadFactory(String.format("LwM2M %s channel update registered", SERVICE_CHANNEL))); - this.executorUnRegistered = Executors.newFixedThreadPool(10, + this.executorUnRegistered = Executors.newFixedThreadPool(this.context.getCtxServer().getUnRegisteredPoolSize(), new NamedThreadFactory(String.format("LwM2M %s channel un registered", SERVICE_CHANNEL))); this.converter = LwM2mValueConverterImpl.getInstance(); } @@ -147,13 +147,13 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { public void onRegistered(LeshanServer lwServer, Registration registration, Collection previousObsersations) { executorRegistered.submit(() -> { try { - log.warn("[{}] [{{}] Client: create after Registration", registration.getEndpoint(), registration.getId()); +// log.warn("[{}] [{{}] Client: create after Registration", registration.getEndpoint(), registration.getId()); LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.updateInSessionsLwM2MClient(lwServer, registration); if (lwM2MClient != null) { lwM2MClient.setLwM2MTransportServiceImpl(this); lwM2MClient.setSessionUuid(UUID.randomUUID()); this.sentLogsToThingsboard(LOG_LW2M_INFO + ": Client Registered", registration); - this.setLwM2MClient(lwServer, registration, lwM2MClient); +// this.setLwM2MClient(lwServer, registration, lwM2MClient); SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration); if (sessionInfo != null) { lwM2MClient.setDeviceUuid(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB())); @@ -204,9 +204,10 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { * @param observations - All paths observations before unReg * !!! Warn: if have not finishing unReg, then this operation will be finished on next Client`s connect */ - public void unReg(Registration registration, Collection observations) { + public void unReg(LeshanServer lwServer, Registration registration, Collection observations) { executorUnRegistered.submit(() -> { try { + this.setCancelObservations(lwServer, registration); this.sentLogsToThingsboard(LOG_LW2M_INFO + ": Client unRegistration", registration); this.closeClientSession(registration); } catch (Throwable t) { @@ -279,38 +280,49 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { * @param lwM2MClient - object with All parameters off client */ private void setLwM2MClient(LeshanServer lwServer, Registration registration, LwM2MClient lwM2MClient) { - // #1 - for (Link url : registration.getObjectLinks()) { - LwM2mPath pathIds = new LwM2mPath(url.getUrl()); - if (pathIds.isObjectInstance() && !pathIds.isResource()) { - lwM2MClient.getPendingRequests().add(url.getUrl()); - } - } - // #2 - for (Link url : registration.getObjectLinks()) { - LwM2mPath pathIds = new LwM2mPath(url.getUrl()); - if (pathIds.isObjectInstance() && !pathIds.isResource()) { - lwM2MTransportRequest.sendAllRequest(lwServer, registration, url.getUrl(), GET_TYPE_OPER_READ, ContentFormat.TLV.getName(), - lwM2MClient, null, null, this.context.getCtxServer().getTimeout(), false); - } - } - - // #1 // Arrays.stream(registration.getObjectLinks()).forEach(url -> { // LwM2mPath pathIds = new LwM2mPath(url.getUrl()); // if (pathIds.isObjectInstance() && !pathIds.isResource()) { +// // #1 // lwM2MClient.getPendingRequests().add(url.getUrl()); +// // #2 +// lwM2MTransportRequest.sendAllRequest(lwServer, registration, url.getUrl(), GET_TYPE_OPER_READ, ContentFormat.TLV.getName(), +// lwM2MClient, null, null, this.context.getCtxServer().getTimeout(), false); // } // }); - // #2 -// Arrays.stream(registration.getObjectLinks()).forEach(url -> { +// // #1 +// for (Link url : registration.getObjectLinks()) { +// LwM2mPath pathIds = new LwM2mPath(url.getUrl()); +// if (pathIds.isObjectInstance() && !pathIds.isResource()) { +// lwM2MClient.getPendingRequests().add(url.getUrl()); +// } +// } +// // #2 +// for (Link url : registration.getObjectLinks()) { // LwM2mPath pathIds = new LwM2mPath(url.getUrl()); // if (pathIds.isObjectInstance() && !pathIds.isResource()) { // lwM2MTransportRequest.sendAllRequest(lwServer, registration, url.getUrl(), GET_TYPE_OPER_READ, ContentFormat.TLV.getName(), // lwM2MClient, null, null, this.context.getCtxServer().getTimeout(), false); // } -// }); +// } + + // #1 + Arrays.stream(registration.getObjectLinks()).forEach(url -> { + LwM2mPath pathIds = new LwM2mPath(url.getUrl()); + if (pathIds.isObjectInstance() && !pathIds.isResource()) { + lwM2MClient.getPendingRequests().add(url.getUrl()); + } + }); + + // #2 + Arrays.stream(registration.getObjectLinks()).forEach(url -> { + LwM2mPath pathIds = new LwM2mPath(url.getUrl()); + if (pathIds.isObjectInstance() && !pathIds.isResource()) { + lwM2MTransportRequest.sendAllRequest(lwServer, registration, url.getUrl(), GET_TYPE_OPER_READ, ContentFormat.TLV.getName(), + lwM2MClient, null, null, this.context.getCtxServer().getTimeout(), false); + } + }); } /** @@ -691,24 +703,29 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { * @param values - LwM2mSingleResource response.getContent() * @param path - resource */ - private void onObservationSetResourcesValue(Registration registration, Object value, Map values, String path) { + private void onObservationSetResourcesValue(Registration registration, Object value, Map values, String path) { boolean isChange = false; try { writeLock.lock(); // #1 LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClientWithReg(registration, null); LwM2mPath pathIds = new LwM2mPath(path); - log.warn("#0 nameDevice: [{}] resultIds: [{}] value: [{}], values: [{}] ", lwM2MClient.getDeviceName(), pathIds, value, values); +// log.warn("#0 nameDevice: [{}] resultIds: [{}] value: [{}], values: [{}] ", lwM2MClient.getDeviceName(), pathIds, value, values); ResourceModel.Type resModelType = context.getCtxServer().getResourceModelType(registration, pathIds); ResourceValue resValueOld = lwM2MClient.getResources().get(path); // #2 if (resValueOld.isMultiInstances() && !values.toString().equals(resValueOld.getResourceValue().toString())) { - ResourceValue resourceValue = new ResourceValue(values, null, true); - lwM2MClient.getResources().put(path, resourceValue); + lwM2MClient.getResources().get(path).setValues(values); +// ResourceValue resourceValue = new ResourceValue(values, null, true); +// lwM2MClient.getResources().put(path, resourceValue); isChange = true; } else if (!LwM2MTransportHandler.equalsResourceValue(resValueOld.getValue(), value, resModelType, pathIds)) { - ResourceValue resourceValue = new ResourceValue(null, value, false); - lwM2MClient.getResources().put(path, resourceValue); + lwM2MClient.getResources().get(path).setValue(value); +// ResourceValue resourceValueOld = lwM2MClient.getResources().get(path); +// lwM2MClient.getResources().remove(resourceValueOld); +// ResourceValue resourceValue = new ResourceValue(null, value, false); +// lwM2MClient.getResources().put(path, resourceValue); + log.warn("upDateResize: [{}] [{}] [{}] [{}]", lwM2MClient.getEndPoint(), lwM2MClient.getResources().size(), value, path); isChange = true; } } catch (Exception e) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java index 239a40658f..e7f82db0c4 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java @@ -54,7 +54,6 @@ public class LwM2mServerListener { @Override public void updated(RegistrationUpdate update, Registration updatedRegistration, Registration previousRegistration) { - log.info("updated"); service.updatedReg(lhServer, updatedRegistration); } @@ -64,8 +63,7 @@ public class LwM2mServerListener { @Override public void unregistered(Registration registration, Collection observations, boolean expired, Registration newReg) { - log.info("unregistered"); - service.unReg(registration, observations); + service.unReg(lhServer, registration, observations); } }; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java index 72cb052dc7..fdb2055500 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java @@ -18,6 +18,7 @@ package org.thingsboard.server.transport.lwm2m.server.client; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.model.ObjectModel; +import org.eclipse.leshan.core.node.LwM2mMultipleResource; import org.eclipse.leshan.core.node.LwM2mObjectInstance; import org.eclipse.leshan.core.node.LwM2mPath; import org.eclipse.leshan.core.response.LwM2mResponse; @@ -104,8 +105,8 @@ public class LwM2MClient implements Cloneable { if (objectModel != null) { ((LwM2mObjectInstance)((ReadResponse)resp).getContent()).getResources().forEach((k, v) -> { String rez = pathIds.toString() + "/" + k; - if (objectModel.resources.get(k).multiple){ - this.resources.put(rez, new ResourceValue(v.getValues(), null, true)); + if (((LwM2mObjectInstance) ((ReadResponse) resp).getContent()).getResource(k) instanceof LwM2mMultipleResource){ +// this.resources.put(rez, new ResourceValue(v.getInstances().values(), null, true)); } else { this.resources.put(rez, new ResourceValue(null, v.getValue(), false)); @@ -114,6 +115,7 @@ public class LwM2MClient implements Cloneable { } } }); + if (this.responses.size() == 0) this.responses = new ConcurrentHashMap<>(); } /** diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResourceValue.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResourceValue.java index 2c962a4395..a4a9d54ada 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResourceValue.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResourceValue.java @@ -21,7 +21,7 @@ import java.util.Map; @Data public class ResourceValue { - Map values; + Map values; Object value; boolean multiInstances; diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigBootstrap.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigBootstrap.java index 2e8a00bc5e..c8215b7ef3 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigBootstrap.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigBootstrap.java @@ -32,39 +32,57 @@ import java.util.Map; @ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true') || '${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core'") public class LwM2MTransportConfigBootstrap { - @Getter - @Value("${transport.lwm2m.bootstrap.bind_address:}") - private String bootstrapHost; + @Value("${transport.lwm2m.bootstrap.enable:}") + private Boolean bootstrapEnable; @Getter - @Value("${transport.lwm2m.bootstrap.bind_port:}") - private Integer bootstrapPort; + @Value("${transport.lwm2m.bootstrap.id:}") + private Integer bootstrapServerId; @Getter - @Value("${transport.lwm2m.bootstrap.bind_port_cert:}") - private Integer bootstrapPortCert; + @Value("${transport.lwm2m.bootstrap.secure.start_psk:}") + private Boolean bootstrapStartPsk; + @Getter + @Value("${transport.lwm2m.bootstrap.secure.start_rpk:}") + private Boolean bootstrapStartRpk; @Getter - @Value("${transport.lwm2m.bootstrap.secure.start_all:}") - private boolean bootstrapStartAll; + @Value("${transport.lwm2m.bootstrap.secure.start_x509:}") + private Boolean bootstrapStartX509; @Getter - @Value("${transport.lwm2m.bootstrap.secure.dtls_mode:}") - private Integer bootStrapDtlsMode; + @Value("${transport.lwm2m.bootstrap.bind_address:}") + private String bootstrapHost; @Getter @Value("${transport.lwm2m.bootstrap.secure.bind_address:}") private String bootstrapSecureHost; @Getter - @Value("${transport.lwm2m.bootstrap.secure.bind_port:}") - private Integer bootstrapSecurePort; + @Value("${transport.lwm2m.bootstrap.bind_port_no_sec_psk:}") + private Integer bootstrapPortNoSecPsk; + + @Getter + @Value("${transport.lwm2m.bootstrap.bind_port_no_sec_rpk:}") + private Integer bootstrapPortNoSecRpk; + + @Getter + @Value("${transport.lwm2m.bootstrap.bind_port_no_sec_x509:}") + private Integer bootstrapPortNoSecX509; + + @Getter + @Value("${transport.lwm2m.bootstrap.secure.bind_port_psk:}") + private Integer bootstrapSecurePortPsk; + + @Getter + @Value("${transport.lwm2m.bootstrap.secure.bind_port_rpk:}") + private Integer bootstrapSecurePortRpk; @Getter - @Value("${transport.lwm2m.bootstrap.secure.bind_port_cert:}") - private Integer bootstrapSecurePortCert; + @Value("${transport.lwm2m.bootstrap.secure.bind_port_x509:}") + private Integer bootstrapSecurePortX509; @Getter @Value("${transport.lwm2m.bootstrap.secure.public_x:}") diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigServer.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigServer.java index f2e398f063..e5643a90f2 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigServer.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigServer.java @@ -47,13 +47,6 @@ import java.util.stream.Collectors; @ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true') || '${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core'") public class LwM2MTransportConfigServer { - @Getter - @Value("${transport.lwm2m.timeout:}") - private Long timeout; - - @Getter - @Value("${transport.sessions.report_timeout}") - private long sessionReportTimeout; @Getter private String MODEL_PATH_DEFAULT = "models"; @@ -85,10 +78,6 @@ public class LwM2MTransportConfigServer { @Getter private String BASE_DIR_PATH = System.getProperty("user.dir"); - @Getter - @Value("${transport.lwm2m.model_path_file:}") - private String modelPathFile; - @Getter // private String PATH_DATA_MICROSERVICE = "/usr/share/tb-lwm2m-transport/data$"; private String PATH_DATA = "data"; @@ -98,8 +87,44 @@ public class LwM2MTransportConfigServer { private List modelsValue; @Getter - @Value("${transport.lwm2m.support_deprecated_ciphers_enable:}") - private boolean supportDeprecatedCiphersEnable; + @Value("${transport.lwm2m.timeout:}") + private Long timeout; + + @Getter + @Value("${transport.sessions.report_timeout}") + private long sessionReportTimeout; + + @Getter + @Value("${transport.lwm2m.model_path_file:}") + private String modelPathFile; + + @Getter + @Value("${transport.lwm2m.recommended_ciphers:}") + private boolean recommendedCiphers; + + @Getter + @Value("${transport.lwm2m.recommended_supported_groups:}") + private boolean recommendedSupportedGroups; + + @Getter + @Value("${transport.lwm2m.request_pool_size:}") + private int requestPoolSize; + + @Getter + @Value("${transport.lwm2m.request_error_pool_size:}") + private int requestErrorPoolSize; + + @Getter + @Value("${transport.lwm2m.registered_pool_size:}") + private int registeredPoolSize; + + @Getter + @Value("${transport.lwm2m.update_registered_pool_size:}") + private int updateRegisteredPoolSize; + + @Getter + @Value("${transport.lwm2m.un_registered_pool_size:}") + private int unRegisteredPoolSize; @Getter @Value("${transport.lwm2m.secure.key_store_type:}") @@ -121,6 +146,18 @@ public class LwM2MTransportConfigServer { @Value("${transport.lwm2m.secure.root_alias:}") private String rootAlias; + @Getter + @Value("${transport.lwm2m.server.secure.start_psk:}") + private boolean serverStartPsk; + + @Getter + @Value("${transport.lwm2m.server.secure.start_rpk:}") + private boolean serverStartRpk; + + @Getter + @Value("${transport.lwm2m.server.secure.start_x509:}") + private boolean serverStartX509; + @Getter @Value("${transport.lwm2m.secure.enable_gen_psk_rpk:}") private Boolean enableGenPskRpk; @@ -130,32 +167,37 @@ public class LwM2MTransportConfigServer { private String serverHost; @Getter - @Value("${transport.lwm2m.server.bind_port:}") - private Integer serverPort; + @Value("${transport.lwm2m.server.id:}") + private Integer serverId; + + @Getter + @Value("${transport.lwm2m.server.secure.bind_address:}") + private String serverSecureHost; + @Getter - @Value("${transport.lwm2m.server.bind_port_cert:}") - private Integer serverPortCert; + @Value("${transport.lwm2m.server.bind_port_no_sec_psk:}") + private Integer serverPortNoSecPsk; @Getter - @Value("${transport.lwm2m.server.secure.start_all:}") - private boolean serverStartAll; + @Value("${transport.lwm2m.server.bind_port_no_sec_rpk:}") + private Integer serverPortNoSecRpk; @Getter - @Value("${transport.lwm2m.server.secure.dtls_mode:}") - private Integer serverDtlsMode; + @Value("${transport.lwm2m.server.bind_port_no_sec_x509:}") + private Integer serverPortNoSecX509; @Getter - @Value("${transport.lwm2m.server.secure.bind_address:}") - private String serverSecureHost; + @Value("${transport.lwm2m.server.secure.bind_port_psk:}") + private Integer serverPortPsk; @Getter - @Value("${transport.lwm2m.server.secure.bind_port:}") - private Integer serverSecurePort; + @Value("${transport.lwm2m.server.secure.bind_port_rpk:}") + private Integer serverPortRpk; @Getter - @Value("${transport.lwm2m.server.secure.bind_port_cert:}") - private Integer serverSecurePortCert; + @Value("${transport.lwm2m.server.secure.bind_port_x509:}") + private Integer serverPortX509; @Getter @Value("${transport.lwm2m.server.secure.public_x:}") @@ -173,10 +215,6 @@ public class LwM2MTransportConfigServer { @Value("${transport.lwm2m.server.secure.alias:}") private String serverAlias; - @Getter - @Value("${transport.lwm2m.bootstrap.enable:}") - private Boolean bootstrapEnable; - @Getter @Value("${transport.lwm2m.secure.redis_url:}") private String redisUrl; diff --git a/pom.xml b/pom.xml index 3cbd57e508..6fc9e94051 100755 --- a/pom.xml +++ b/pom.xml @@ -62,10 +62,10 @@ 2.11.3 2.11.3 2.2.6 - 2.2.3 - 1.0.1 - 1.0.1 - 1.0.0 + 2.6.0 + 1.3.0 + 1.3.0 + 1.3.0 2.6.2 2.3.30 1.6.2 @@ -1166,11 +1166,6 @@ leshan-core ${leshan-core.version} - - org.eclipse.californium - californium-core - ${californium.version} - org.eclipse.californium californium-core diff --git a/transport/lwm2m/pom.xml b/transport/lwm2m/pom.xml index 1d7619a2ad..addbeb9d7b 100644 --- a/transport/lwm2m/pom.xml +++ b/transport/lwm2m/pom.xml @@ -45,11 +45,38 @@ + + org.thingsboard.common.transport + transport-api + + + org.springframework + spring-context-support + + + org.springframework + spring-context + + + org.slf4j + slf4j-api + + + org.slf4j + log4j-over-slf4j + + + ch.qos.logback + logback-core + + + ch.qos.logback + logback-classic + org.eclipse.leshan leshan-server-cf - org.eclipse.leshan leshan-client-cf @@ -59,7 +86,6 @@ org.eclipse.leshan leshan-server-redis - org.springframework.boot spring-boot-starter-test @@ -78,32 +104,22 @@ org.eclipse.californium californium-core - - - org.eclipse.californium - element-connector test-jar test - - org.thingsboard.common.transport - lwm2m - - - org.thingsboard.common - queue - - - org.springframework.boot - spring-boot-starter-web + org.eclipse.californium + californium-core + + + + - com.sun.winsw - winsw - bin - exe - provided + org.eclipse.californium + element-connector + test-jar + test diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index d6fe7b5b1f..f25dd2bb59 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -42,6 +42,7 @@ zk: # LWM2M server parameters transport: + # Local LwM2M transport parameters lwm2m: # Enable/disable lvm2m transport protocol. enabled: "${LWM2M_ENABLED:true}" @@ -51,7 +52,13 @@ transport: timeout: "${LWM2M_TIMEOUT:120000}" # model_path_file: "${LWM2M_MODEL_PATH_FILE:./common/transport/lwm2m/src/main/resources/models/}" model_path_file: "${LWM2M_MODEL_PATH_FILE:}" - support_deprecated_ciphers_enable: "${LWM2M_SUPPORT_DEPRECATED_CIPHERS_ENABLED:true}" + recommended_ciphers: "${LWM2M_RECOMMENDED_CIPHERS:false}" + recommended_supported_groups: "${LWM2M_RECOMMENDED_SUPPORTED_GROUPS:false}" + request_pool_size: "${LWM2M_REQUEST_POOL_SIZE:100}" + request_error_pool_size: "${LWM2M_REQUEST_ERROR_POOL_SIZE:10}" + registered_pool_size: "${LWM2M_REGISTERED_POOL_SIZE:10}" + update_registered_pool_size: "${LWM2M_UPDATE_REGISTERED_POOL_SIZE:10}" + un_registered_pool_size: "${LWM2M_UN_REGISTERED_POOL_SIZE:10}" secure: # Only Certificate_x509: # To get helps about files format and how to generate it, see: https://github.com/eclipse/leshan/wiki/Credential-files-format @@ -64,24 +71,19 @@ transport: root_alias: "${LWM2M_SERVER_ROOT_CA:rootca}" enable_gen_psk_rpk: "${ENABLE_GEN_PSK_RPK:true}" server: + id: "${LWM2M_SERVER_ID:123}" bind_address: "${LWM2M_BIND_ADDRESS:0.0.0.0}" - bind_port: "${LWM2M_BIND_PORT:5685}" - bind_port_cert: "${LWM2M_BIND_PORT_CERT:5687}" + bind_port_no_sec_psk: "${LWM2M_BIND_PORT_NO_SEC_PSK:5685}" + bind_port_no_sec_rpk: "${LWM2M_BIND_PORT_NO_SEC_RPK:5687}" + bind_port_no_sec_x509: "${LWM2M_BIND_PORT_NO_SEC_X509:5689}" secure: - start_all: "${START_SERVER_ALL:true}" - #leshan.core (V1_1) - #DTLS security modes: - #0: Pre-Shared Key mode - #1: Raw Public Key mode - #2: Certificate mode X509 - #3: NoSec mode * - #OMA-TS-LightweightM2M_Core-V1_1_1-20190617-A (add) - #4: Certificate mode X509 with EST - # If only startAll == false - dtls_mode: "${LWM2M_SECURITY_MODE:1}" bind_address: "${LWM2M_BIND_ADDRESS:0.0.0.0}" - bind_port: "${LWM2M_BIND_PORT_SEC:5686}" - bind_port_cert: "${LWM2M_BIND_PORT_SEC_CERT:5688}" + start_psk: "${START_SERVER_PSK:true}" + start_rpk: "${START_SERVER_RPK:true}" + start_x509: "${START_SERVER_X509:true}" + bind_port_psk: "${LWM2M_BIND_PORT_SEC_PSK:5686}" + bind_port_rpk: "${LWM2M_BIND_PORT_SEC_RPK:5688}" + bind_port_x509: "${LWM2M_BIND_PORT_SEC_X509:5690}" # Only RPK: Public & Private Key # create_rpk: "${CREATE_RPK:}" public_x: "${LWM2M_SERVER_PUBLIC_X:405354ea8893471d9296afbc8b020a5c6201b0bb25812a53b849d4480fa5f069}" @@ -91,16 +93,19 @@ transport: alias: "${LWM2M_KEYSTORE_ALIAS_SERVER:server}" bootstrap: enable: "${BOOTSTRAP:true}" + id: "${LWM2M_SERVER_ID:111}" bind_address: "${LWM2M_BIND_ADDRESS_BS:0.0.0.0}" - bind_port: "${LWM2M_BIND_PORT_BS:5689}" - bind_port_cert: "${LWM2M_BIND_PORT_SER_BS:5691}" + bind_port_no_sec_psk: "${LWM2M_BIND_PORT_NO_SEC_BS:5691}" + bind_port_no_sec_rpk: "${LWM2M_BIND_PORT_NO_SEC_BS:5693}" + bind_port_no_sec_x509: "${LWM2M_BIND_PORT_NO_SEC_BS:5695}" secure: - start_all: "${START_BOOTSTRAP_ALL:true}" - # If only startAll == false - dtls_mode: "${LWM2M_SECURITY_MODE_BS:1}" bind_address: "${LWM2M_BIND_ADDRESS_BS:0.0.0.0}" - bind_port: "${LWM2M_BIND_PORT_SEC_BS:5690}" - bind_port_cert: "${LWM2M_BIND_PORT_SEC_CERT_BS:5692}" + start_psk: "${START_SERVER_PSK_BS:true}" + start_rpk: "${START_SERVER_RPK_BS:true}" + start_x509: "${START_SERVER_X509_BS:true}" + bind_port_psk: "${LWM2M_BIND_PORT_SEC_PSK_BS:5692}" + bind_port_rpk: "${LWM2M_BIND_PORT_SER_RPK_BS:5694}" + bind_port_x509: "${LWM2M_BIND_PORT_SEC_X509_BS:5696}" # Only RPK: Public & Private Key public_x: "${LWM2M_SERVER_PUBLIC_X_BS:993ef2b698c6a9c0c1d8be78b13a9383c0854c7c7c7a504d289b403794648183}" public_y: "${LWM2M_SERVER_PUBLIC_Y_BS:267412d5fc4e5ceb2257cb7fd7f76ebdac2fa9aa100afb162e990074cc0bfaa2}" diff --git a/ui-ngx/angular.json b/ui-ngx/angular.json index 3cad30304a..3cc2d92d57 100644 --- a/ui-ngx/angular.json +++ b/ui-ngx/angular.json @@ -247,6 +247,7 @@ }, "defaultProject": "thingsboard", "cli": { - "packageManager": "yarn" + "packageManager": "yarn", + "analytics": false } -} +} \ No newline at end of file diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.ts index 20a72d8dcd..31ab078485 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.ts @@ -25,7 +25,7 @@ import { import { ControlValueAccessor, FormBuilder, - FormGroup, NG_VALIDATORS, + FormGroup, NG_VALUE_ACCESSOR, Validators } from "@angular/forms"; import { coerceBooleanProperty } from "@angular/cdk/coercion"; diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.ts index 62f516b660..9c62b02b49 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.ts @@ -16,12 +16,11 @@ import { Component, Inject, OnInit } from '@angular/core'; import { DialogComponent } from '@shared/components/dialog.component'; -import { ControlValueAccessor, FormBuilder, FormGroup } from '@angular/forms'; +import { FormBuilder, FormGroup } from '@angular/forms'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { Router } from '@angular/router'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { TranslateService } from '@ngx-translate/core'; export interface Lwm2mObjectAddInstancesData { instancesIds: Set; diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resource.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resource.component.ts index f94cd589ae..9a909a41af 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resource.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resource.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, EventEmitter, forwardRef, Input, OnInit, Output, ViewChild } from "@angular/core"; +import { Component, forwardRef, Input, OnInit } from "@angular/core"; import { ControlValueAccessor, FormArray, FormBuilder, @@ -27,7 +27,7 @@ import { } from '@home/components/profile/device/lwm2m/profile-config.models'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; -import { deepClone, isUndefined } from '@core/utils'; +import { deepClone } from '@core/utils'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; @Component({ diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts index 8482fde97a..e506510663 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts @@ -44,7 +44,6 @@ import { Lwm2mObjectAddInstancesComponent, Lwm2mObjectAddInstancesData } from '@home/components/profile/device/lwm2m/lwm2m-object-add-instances.component'; -import { Control } from 'leaflet'; @Component({ selector: 'tb-profile-lwm2m-observe-attr-telemetry', diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/profile-config.models.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/profile-config.models.ts index c626138828..20a68765a9 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/profile-config.models.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/profile-config.models.ts @@ -25,11 +25,7 @@ export const DEFAULT_ID_SERVER = 123; export const DEFAULT_ID_BOOTSTRAP = 111; export const DEFAULT_HOST_NAME = "localhost"; export const DEFAULT_PORT_SERVER_NO_SEC = 5685; -export const DEFAULT_PORT_SERVER_SEC = 5686; -export const DEFAULT_PORT_SERVER_SEC_CERT = 5688; -export const DEFAULT_PORT_BOOTSTRAP_NO_SEC = 5689; -export const DEFAULT_PORT_BOOTSTRAP_SEC = 5690; -export const DEFAULT_PORT_BOOTSTRAP_SEC_CERT = 5692; +export const DEFAULT_PORT_BOOTSTRAP_NO_SEC = 5691; export const DEFAULT_CLIENT_HOLD_OFF_TIME = 1; export const DEFAULT_LIFE_TIME = 300; export const DEFAULT_DEFAULT_MIN_PERIOD = 1; @@ -118,7 +114,7 @@ export function getDefaultBootstrapServersSecurityConfig(): BootstrapServersSecu export function getDefaultBootstrapServerSecurityConfig(hostname: any): ServerSecurityConfig { return { host: hostname, - port: getDefaultPortBootstrap(), + port: DEFAULT_PORT_BOOTSTRAP_NO_SEC, bootstrapServerIs: true, securityMode: SECURITY_CONFIG_MODE.NO_SEC.toString(), serverPublicKey: '', @@ -131,20 +127,10 @@ export function getDefaultBootstrapServerSecurityConfig(hostname: any): ServerSe export function getDefaultLwM2MServerSecurityConfig(hostname): ServerSecurityConfig { const DefaultLwM2MServerSecurityConfig = getDefaultBootstrapServerSecurityConfig(hostname); DefaultLwM2MServerSecurityConfig.bootstrapServerIs = false; - DefaultLwM2MServerSecurityConfig.port = getDefaultPortServer(); + DefaultLwM2MServerSecurityConfig.port = DEFAULT_PORT_SERVER_NO_SEC; DefaultLwM2MServerSecurityConfig.serverId = DEFAULT_ID_SERVER; return DefaultLwM2MServerSecurityConfig; } -//ok -export function getDefaultPortBootstrap(securityMode?: string): number { - return (!securityMode || securityMode === SECURITY_CONFIG_MODE.NO_SEC.toString()) ? DEFAULT_PORT_BOOTSTRAP_NO_SEC : - (securityMode === SECURITY_CONFIG_MODE.X509.toString()) ? DEFAULT_PORT_BOOTSTRAP_SEC_CERT : DEFAULT_PORT_BOOTSTRAP_SEC; -} -//ok -export function getDefaultPortServer(securityMode?: string): number { - return (!securityMode || securityMode === SECURITY_CONFIG_MODE.NO_SEC.toString()) ? DEFAULT_PORT_SERVER_NO_SEC : - (securityMode === SECURITY_CONFIG_MODE.X509.toString()) ? DEFAULT_PORT_SERVER_SEC_CERT : DEFAULT_PORT_SERVER_SEC; -} //ok function getDefaultProfileBootstrapSecurityConfig(hostname: any): BootstrapSecurityConfig { @@ -197,16 +183,3 @@ export interface ObjectLwM2M { instances?: Instance [] } -export function getChangeInstancesIds (): ChangeInstancesIds { - let changeInstancesIds: ChangeInstancesIds; - changeInstancesIds.add = new Set(); - changeInstancesIds.del = new Set(); - return changeInstancesIds; - -} - -export interface ChangeInstancesIds { - add: Set, - del: Set -} - From fb193bf66e52ef2b39fc80fb55b08b79792a0c4a Mon Sep 17 00:00:00 2001 From: lsyer Date: Tue, 12 Jan 2021 15:20:01 +0800 Subject: [PATCH 025/249] Update locale.constant-zh_CN.json --- .../src/assets/locale/locale.constant-zh_CN.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json index 28e38022a9..12f0024529 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json @@ -339,7 +339,7 @@ "api-usage": { "api-usage": "Api 使用统计", "data-points": "数据点", - "data-points-storage-days": "数据点存储天数", + "data-points-storage-days": "日存储数据点数", "email": "Email", "email-messages": "Email messages", "email-messages-daily-activity": "Email messages daily activity", @@ -1646,7 +1646,7 @@ "access-token": "访问令牌", "tls": "TLS" }, - "storage": "Storage", + "storage": "存储", "storage-max-file-records": "文件中的最大记录数", "storage-max-files": "最大文件数", "storage-max-files-min": "最小值为1。", @@ -1665,7 +1665,7 @@ "storage-type": "存储类型", "storage-types": { "file-storage": "文件存储", - "memory-storage": "存储器" + "memory-storage": "内存存储" }, "thingsboard": "ThingsBoard", "thingsboard-host": "ThingsBoard主机", @@ -2016,7 +2016,7 @@ "create-new-tenant-profile": "创建一个新的!", "data": "纵断面数据", "default": "默认", - "default-storage-ttl-days": "默认存储TTL天(0-无限制)", + "default-storage-ttl-days": "默认存储 TTL 天数(0-无限制)", "default-storage-ttl-days-range": "不能为负存储天数", "default-storage-ttl-days-required": "默认存储 TTL 天数必填。", "delete": "删除租户配置", @@ -2027,9 +2027,9 @@ "description": "说明", "edit": "编辑租户配置", "idCopiedMessage": "租户配置Id已复制到剪贴板", - "max-d-p-storage-days": "最大数据点存储天数(0-无限制)", - "max-d-p-storage-days-range": "最大数据点存储天数不能为负数", - "max-d-p-storage-days-required": "最大数据点存储天数必填。", + "max-d-p-storage-days": "最大日存储数据点数(0-无限制)", + "max-d-p-storage-days-range": "最大日存储数据点数不能为负数", + "max-d-p-storage-days-required": "最大日存储数据点数必填。", "max-emails": "发送的最大电子邮件数(0-无限制)", "max-emails-range": "发送的最大电子邮件数不能为负数", "max-emails-required": "最大电子邮件发送数必填。", From cb3353a32d3ea39b1645f8ee9f3368219b417435 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 12 Jan 2021 11:31:20 +0200 Subject: [PATCH 026/249] Lwm2m: backEnd: refactoring start server/bootstrap without different secure --- application/src/main/resources/thingsboard.yml | 2 +- ...wM2MTransportBootstrapServerConfiguration.java | 5 ++++- .../LwM2MTransportBootstrapServerInitializer.java | 8 ++++---- .../server/LwM2MTransportServerConfiguration.java | 15 +++++++++------ .../server/LwM2MTransportServerInitializer.java | 6 +++--- 5 files changed, 21 insertions(+), 15 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 8c2d7e1702..51c1f4f353 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -635,7 +635,7 @@ transport: private_s: "${LWM2M_SERVER_PRIVATE_S_BS:9dbdbb073fc63570693a9aaf1013414e261c571f27e27fc6a8c1c2ad9347875a}" # Only Certificate_x509: alias: "${LWM2M_KEYSTORE_ALIAS_BOOTSTRAP:bootstrap}" - # Redis + # Redis redis_url: "${LWM2M_REDIS_URL:''}" swagger: diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerConfiguration.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerConfiguration.java index 17999326d7..09233b5d3b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerConfiguration.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerConfiguration.java @@ -61,7 +61,7 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandle @Slf4j @Component -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true'&& '${transport.lwm2m.bootstrap.enable:false}'=='true') || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true'&& '${transport.lwm2m.bootstrap.enable}'=='true')") +@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true'&& '${transport.lwm2m.bootstrap.enable:false}'=='true') || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled:false}'=='true'&& '${transport.lwm2m.bootstrap.enable:false}'=='true')") public class LwM2MTransportBootstrapServerConfiguration { private PublicKey publicKey; private PrivateKey privateKey; @@ -80,18 +80,21 @@ public class LwM2MTransportBootstrapServerConfiguration { @Primary @Bean(name = "leshanBootstrapX509") + @ConditionalOnExpression("('${transport.lwm2m.bootstrap.secure.start_x509:false}'=='true')") public LeshanBootstrapServer getLeshanBootstrapServerX509() { log.info("Prepare and start BootstrapServerX509... PostConstruct"); return getLeshanBootstrapServer(this.contextBs.getCtxBootStrap().getBootstrapPortNoSecX509(), this.contextBs.getCtxBootStrap().getBootstrapSecurePortX509(), X509); } @Bean(name = "leshanBootstrapPsk") + @ConditionalOnExpression("('${transport.lwm2m.bootstrap.secure.start_psk:false}'=='true')") public LeshanBootstrapServer getLeshanBootstrapServerPsk() { log.info("Prepare and start BootstrapServerRsk... PostConstruct"); return getLeshanBootstrapServer(this.contextBs.getCtxBootStrap().getBootstrapPortNoSecPsk(), this.contextBs.getCtxBootStrap().getBootstrapSecurePortPsk(), PSK); } @Bean(name = "leshanBootstrapRpk") + @ConditionalOnExpression("('${transport.lwm2m.bootstrap.secure.start_rpk:false}'=='true')") public LeshanBootstrapServer getLeshanBootstrapServerRpk() { log.info("Prepare and start BootstrapServerRpk... PostConstruct"); return getLeshanBootstrapServer(this.contextBs.getCtxBootStrap().getBootstrapPortNoSecRpk(), this.contextBs.getCtxBootStrap().getBootstrapSecurePortRpk(), RPK); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerInitializer.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerInitializer.java index 6ffa3e8bdf..68bc6ee51c 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerInitializer.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerInitializer.java @@ -27,18 +27,18 @@ import javax.annotation.PreDestroy; @Slf4j @Service -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled}'=='true'&& '${transport.lwm2m.bootstrap.enable}'=='true') || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true'&& '${transport.lwm2m.bootstrap.enable}'=='true')") +@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true'&& '${transport.lwm2m.bootstrap.enable:false}'=='true') || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled:false}'=='true'&& '${transport.lwm2m.bootstrap.enable:false}'=='true')") public class LwM2MTransportBootstrapServerInitializer { - @Autowired + @Autowired(required = false) @Qualifier("leshanBootstrapX509") private LeshanBootstrapServer lhBServerCert; - @Autowired + @Autowired(required = false) @Qualifier("leshanBootstrapPsk") private LeshanBootstrapServer lhBServerPsk; - @Autowired + @Autowired(required = false) @Qualifier("leshanBootstrapRpk") private LeshanBootstrapServer lhBServerRpk; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerConfiguration.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerConfiguration.java index 71fc65967b..1b9c51b9ec 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerConfiguration.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerConfiguration.java @@ -85,24 +85,27 @@ public class LwM2MTransportServerConfiguration { private LwM2mInMemorySecurityStore lwM2mInMemorySecurityStore; @Primary - @Bean(name = "leshanServerX509") - public LeshanServer getLeshanServerX509() { - log.info("Starting LwM2M transport ServerX509... PostConstruct"); - return getLeshanServer(this.context.getCtxServer().getServerPortNoSecX509(), this.context.getCtxServer().getServerPortX509(), X509); - } - @Bean(name = "leshanServerPsk") + @ConditionalOnExpression("('${transport.lwm2m.server.secure.start_psk:false}'=='true')") public LeshanServer getLeshanServerPsk() { log.info("Starting LwM2M transport ServerPsk... PostConstruct"); return getLeshanServer(this.context.getCtxServer().getServerPortNoSecPsk(), this.context.getCtxServer().getServerPortPsk(), PSK); } @Bean(name = "leshanServerRpk") + @ConditionalOnExpression("('${transport.lwm2m.server.secure.start_rpk:false}'=='true')") public LeshanServer getLeshanServerRpk() { log.info("Starting LwM2M transport ServerRpk... PostConstruct"); return getLeshanServer(this.context.getCtxServer().getServerPortNoSecRpk(), this.context.getCtxServer().getServerPortRpk(), RPK); } + @Bean(name = "leshanServerX509") + @ConditionalOnExpression("('${transport.lwm2m.server.secure.start_x509:false}'=='true')") + public LeshanServer getLeshanServerX509() { + log.info("Starting LwM2M transport ServerX509... PostConstruct"); + return getLeshanServer(this.context.getCtxServer().getServerPortNoSecX509(), this.context.getCtxServer().getServerPortX509(), X509); + } + private LeshanServer getLeshanServer(Integer serverPortNoSec, Integer serverSecurePort, LwM2MSecurityMode dtlsMode) { LeshanServerBuilder builder = new LeshanServerBuilder(); builder.setLocalAddress(this.context.getCtxServer().getServerHost(), serverPortNoSec); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerInitializer.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerInitializer.java index 6fbcb78f9c..74a37938b3 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerInitializer.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerInitializer.java @@ -35,15 +35,15 @@ public class LwM2MTransportServerInitializer { @Autowired private LwM2MTransportServiceImpl service; - @Autowired + @Autowired(required = false) @Qualifier("leshanServerX509") private LeshanServer lhServerX509; - @Autowired + @Autowired(required = false) @Qualifier("leshanServerPsk") private LeshanServer lhServerPsk; - @Autowired + @Autowired(required = false) @Qualifier("leshanServerRpk") private LeshanServer lhServerRpk; From f0ff92eef569be0413f60f269494026d44ff9137 Mon Sep 17 00:00:00 2001 From: Viacheslav Kukhtyn Date: Thu, 14 Jan 2021 10:32:01 +0200 Subject: [PATCH 027/249] Update headers --- .../rule/engine/credentials/AnonymousCredentials.java | 2 +- .../rule/engine/mqtt/credentials/MqttAnonymousCredentials.java | 2 +- .../rule/engine/mqtt/credentials/MqttCertPemCredentials.java | 2 +- .../rule/engine/rest/credentials/HttpAnonymousCredentials.java | 2 +- .../rule/engine/rest/credentials/HttpBasicCredentials.java | 2 +- .../rule/engine/rest/credentials/HttpCertPemCredentials.java | 2 +- .../rule/engine/rest/credentials/HttpClientCredentials.java | 2 +- .../rule/engine/rest/credentials/HttpBasicCredentialsTest.java | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/AnonymousCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/AnonymousCredentials.java index 176899341b..1228256b30 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/AnonymousCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/AnonymousCredentials.java @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2020 The Thingsboard Authors + * Copyright © 2016-2021 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttAnonymousCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttAnonymousCredentials.java index af6eed1cc2..dd827f12ce 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttAnonymousCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttAnonymousCredentials.java @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2020 The Thingsboard Authors + * Copyright © 2016-2021 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttCertPemCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttCertPemCredentials.java index 0aef057601..aaf5a1f927 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttCertPemCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttCertPemCredentials.java @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2020 The Thingsboard Authors + * Copyright © 2016-2021 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpAnonymousCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpAnonymousCredentials.java index 5de4b2f8f5..3b7eb0b12b 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpAnonymousCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpAnonymousCredentials.java @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2020 The Thingsboard Authors + * Copyright © 2016-2021 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpBasicCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpBasicCredentials.java index 3d2d65bebd..cf29cd928a 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpBasicCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpBasicCredentials.java @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2020 The Thingsboard Authors + * Copyright © 2016-2021 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpCertPemCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpCertPemCredentials.java index 3aac4a596f..bdc1d3b264 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpCertPemCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpCertPemCredentials.java @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2020 The Thingsboard Authors + * Copyright © 2016-2021 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpClientCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpClientCredentials.java index 0f81f6ad8b..4e581354b1 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpClientCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpClientCredentials.java @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2020 The Thingsboard Authors + * Copyright © 2016-2021 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/credentials/HttpBasicCredentialsTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/credentials/HttpBasicCredentialsTest.java index abdbd76cc4..755735f1d7 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/credentials/HttpBasicCredentialsTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/credentials/HttpBasicCredentialsTest.java @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2020 The Thingsboard Authors + * Copyright © 2016-2021 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From 84698ad554f555b270214e8b00d20dee86e8f2bb Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Thu, 14 Jan 2021 16:04:58 +0200 Subject: [PATCH 028/249] Lwm2m: front - fix bug /../../ --- ...TransportBootstrapServerConfiguration.java | 3 +- .../LwM2MTransportServerConfiguration.java | 29 ++++++++++++++++++ .../resources/credentials/serverKeyStore.jks | Bin 5716 -> 5708 bytes .../credentials/shell/lwM2M_credentials.sh | 3 ++ .../credentials/shell/lwM2M_keygen.properties | 2 +- .../lwm2m/LwM2MTransportConfigBootstrap.java | 5 --- .../lwm2m/LwM2MTransportConfigServer.java | 2 +- .../main/data/credentials/serverKeyStore.jks | Bin 5716 -> 5708 bytes .../lwm2m-device-config-server.component.ts | 2 +- ...ofile-transport-configuration.component.ts | 6 ++-- ...m2m-object-add-instances-list.component.ts | 4 +-- .../lwm2m/lwm2m-object-list.component.ts | 8 ++--- 12 files changed, 45 insertions(+), 19 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerConfiguration.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerConfiguration.java index 09233b5d3b..13584cadb5 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerConfiguration.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerConfiguration.java @@ -245,8 +245,7 @@ public class LwM2MTransportBootstrapServerConfiguration { } if (serverCertificate != null) { builder.setCertificateChain(new X509Certificate[]{serverCertificate}); - this.contextBs.getCtxBootStrap().setBootstrapCertificate(serverCertificate); - infoParamsX509(serverCertificate); + this.infoParamsX509(serverCertificate); } } catch (Exception ex) { log.error("[{}] Unable to load KeyStore files server", ex.getMessage()); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerConfiguration.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerConfiguration.java index 1b9c51b9ec..c6ce086446 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerConfiguration.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerConfiguration.java @@ -52,6 +52,7 @@ import java.security.KeyFactory; import java.security.KeyStoreException; import java.security.PrivateKey; import java.security.PublicKey; +import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; import java.security.interfaces.ECPublicKey; import java.security.spec.ECGenParameterSpec; @@ -306,8 +307,36 @@ public class LwM2MTransportServerConfiguration { PrivateKey privateKey = (PrivateKey) this.context.getCtxServer().getKeyStoreValue().getKey(this.context.getCtxServer().getServerAlias(), this.context.getCtxServer().getKeyStorePasswordServer() == null ? null : this.context.getCtxServer().getKeyStorePasswordServer().toCharArray()); builder.setPrivateKey(privateKey); builder.setCertificateChain(new X509Certificate[]{serverCertificate}); + this.infoParamsX509(serverCertificate, privateKey); } catch (Exception ex) { log.error("[{}] Unable to load KeyStore files server", ex.getMessage()); } +// /** +// * For deb => KeyStorePathFile == yml or commandline: KEY_STORE_PATH_FILE +// * For idea => KeyStorePathResource == common/transport/lwm2m/src/main/resources/credentials: in LwM2MTransportContextServer: credentials/serverKeyStore.jks +// */ +// try { +// X509Certificate serverCertificate = (X509Certificate) this.context.getCtxServer().getKeyStoreValue().getCertificate(this.context.getCtxServer().getServerPrivateS()); +// this.privateKey = (PrivateKey) this.context.getCtxServer().getKeyStoreValue().getKey(this.context.getCtxServer().getServerAlias(), this.context.getCtxServer().getKeyStorePasswordServer() == null ? null : this.context.getCtxServer().getKeyStorePasswordServer().toCharArray()); +// if (this.privateKey != null && this.privateKey.getEncoded().length > 0) { +// builder.setPrivateKey(this.privateKey); +// } +// if (serverCertificate != null) { +// builder.setCertificateChain(new X509Certificate[]{serverCertificate}); +// this.infoParamsX509(serverCertificate); +// } +// } catch (Exception ex) { +// log.error("[{}] Unable to load KeyStore files server", ex.getMessage()); +// } + } + + private void infoParamsX509(X509Certificate certificate, PrivateKey privateKey) { + try { + log.info("Server uses X509 : \n X509 Certificate (Hex): [{}] \n Private Key (Hex): [{}]", + Hex.encodeHexString(certificate.getEncoded()), + Hex.encodeHexString(privateKey.getEncoded())); + } catch (CertificateEncodingException e) { + log.error("", e); + } } } diff --git a/common/transport/lwm2m/src/main/resources/credentials/serverKeyStore.jks b/common/transport/lwm2m/src/main/resources/credentials/serverKeyStore.jks index b5b6c9fa3c43118262f4c89b1ba319ef09b694d0..e1d6deff4b3fd948655f802da4ad65f0ba568f4a 100644 GIT binary patch delta 5500 zcmYM2Wl+=&*T!jBSV}sSl;&oa5|9p+ZjtU@Lb~J+OCuq|QqtYsu}F7FH-dn4E+q)> zJ?}j8JfE(a>ztY2IoJ7iW_iYVm?3b=cNplH{|Y(|h%5YE_zfXCE_x1};sOg!aRPx; z93(KySOyFXE^HOWag!{fQfkM{^n$cphcPhGdNr`#Wt>Q!PDa6mlL-fIR>V+JVL!8t z6X=^CxJmuvKUmO}t4=wD7icL2NvU3iy9#}u2|GX)yjJJ&myU34J;XRUYa_+b3b;ls zCJYD@3qv77La!iDC_j`R5@yYLQt^XkGc~Lo7};0m1nX`Ph<+;prApPQ&uuKCeeY#=-v#&G!-tyqzja z?PT-IcbtWaL_!eim5B-H;^6jgHUM*-G4I&kwb}IfYIF1tkK-iywDN@F=&DR&GZTifsnouggpyc{<&+3#<$DKD#OS`{%gzII<^|pUAg$=My$RP+=yDd3093CqiMN>a7JG7N!Z>bElZk_I`x8f)- z<(&QL?UUDOcA<70GZc7dmyx;QPYMbIU*AWvrl$SM^8k2TN(&6&0@`XKmvFLP0(-@Dkmu?=y+Vo5t%POsjw_UayDi|^4A(xHT zWSrwk=y5|_OhsP}P8n{wj8zmRQW2kDN`@H0q-CI1_R36?Z&FTod*j4Q2@W=~I|J_Z zG#pI;jmh_EuWq)~R`T&Ec(-ZpJOvY?6OI#qN}VINH(dL|pqgKb zEjT*BO8y?mCY*Sa%ZZipIz-}#XUezsw6{Wh+BAxdn4tbV)fV=-vG)ZRCLq@}NwZUl z;y5X5Z^aJA=8n#sD=hq?tdaN_dvX6*b!`}+Q&JgJ8Gh7#P{4!-G*z99v~B8W;4S@eU5`aG>T#I zRLr?5Nd<-g(fXtCLPBIpns}A<Iw4B{4zIU#XvF$-^V6d3C=@@OJ$1i`ztU*=+J;1rKN{v1$nkC`xOShrf5FGf5jv z7ZJ)@!%t>dj7GaGTIGpKXcU}dvfG8pd;lwzAl{G#QqG>IRuwyE;{{DjO3BT`Z#}#G zC5KeU`w=BZ*JonpU>=x^@|YC!I7 z@pzOMc)nSq(<{HN$%pk56@{s`B{W7z!y9u!(U=+b22(#4tPSK@O^J&xEC%OUv+F3vo zbo@l*?CI}tEQU?r^QQy&x2iY7; z|I)xS1*sl}RrQ4jXr#>>;v0RO=L`xd1#LxNTD6}gfhQg=F|-R`Si8OLs?e7?7z=0j z7+PFWfKU7GRHdAmeq-zlChfl4czLfuK01DD_{PO1h6m4c`Wd4gEC3FTkD~s)O+~|Hmv+^v7?gcXW(k+#$=0yE~pvhUNBHXPbOTM?GA z_sOZQ^`aNVtbDVTBT*b@jz+VP29)6p^g`p!E&b=5Bvm$}@x z>gDWT4cT#eGIJz>=!C{x!Rv0FVIm)NNbHIaZ>)ar5I{wWpL*tT{7{+El|kZl$5O*C zKfrf!i3prV+S1iyA*K^mj6d1!;_e~mq%}wtS1`Euc!vXxB12|_RXP zHj9Pv-Zzn24aR;4cf3m`F)L}}Zw1|GwbqYV_@nt(tM__;512+xZ7NM-4jE@v?sfMR zYBth(0^RA4-tB?BPvDdm9B70b{;pxq6aK=B=W4O+{4d??pK=>)AeY`t_h0(x>2yk? zS6x<9_eI~?5~|4c$svli{c|@x5V-l3luJIwkk3j!e;m;Q#CY8q9shX{BB?7;bMr_( z4*%w%D*a-cj1m0BKw1E>QRUQjSM$h~*+y<(77OckpXTxEQU^oO7fJi0HV3ZbM5N@vvIB_(!u$HhGz59mF zNUcOx6hbymgg1aeXgD`d9ilvIuAkzka=T3RTly7($P%GF^**l3gI*!h^zB=YMp@m3 z`3RAZP$>d`d$c|=E7tK0@WLc-N%+$maQ!g08T9Cm-NO5~X*8;HsqP-eEP^Y9qQNx# zJl0cgJIOyBNvVz1_4g};A}?V?AHHubc`kE(KzgLRkpAkm^aEZ(G3=gYU%!UiaS z{3|m5zY@IL&}^@%VK?@8IGeVYHC28U2T|C@epdHphg|I> z#4{1O(Duj=RS_osXsAy0L;Xq;bhPA4B0eoV-FEY0sEyQ2+t%*8H(n3`HHN_L3TY@H zNGaAk`87peDoAYwIS6U8&v!w@u^6RZ-^`7BF>@*&Qw}pu%4;fPFMO@#q@Jhx9f|C9 z#@NN4kDa0Wlq#>Knt~P6l;uKRQy>L8n$pzZ&zJA66;QSPiaZN6N{6#aBOSFEGd~K3 zRLTDKO~Qqp?@R&C$R_|}c{p2piAqGrzu97xM4Zz;j;A#USrRfVz+o~h9738J2Ks%K zaxLyS#gg=uBl~bdel&}zQ94GWf`6fItTchGm8l%OiG_C3KPGf)_m8`fs-hhIiRw_y z>fU&fduMCUC{n>Q+6`WCCd^!)LB7FlM8b+A7VT0BxXT-YRRHCYVERdULy8wcxV$-n z+mcf|a}^&V>~=R?lDaQn-Ofd!r|A^T!`gk%3iE%^><>x5COx6GzNS6~=_w@ycHF<+ zUyfPx389@nqAE;Wen}G4ym?%V)s^4hTGOnO zf`=@*9#&QN%>aK?K`XaEKdl$06iD`iM8bNuv;;LSuFaat%w5I$@%kDn7*2zWD7}12 zw^;0B?pO!%esOrSQreF3ef=^@u%8+GRc`wYw7Oz}rx5Rc-4>{eu)hoyC$rl#;+Pwf zCC?r6W#k%V^@7<}V$K#2YcSqi=MYiW{Mc-cCHa@S579e5!%ax{EybyhpdcpVj^~I&k z){h3fR@d(P* z6h(|M^Aqj|Y?@XLr`aNM`6qh1g?#+T)t=^|!!GxbC9nF6qk?*(JgJY|sV!Ds!Tbi& zJ9@we!vl6@@IF~&U*tJDd%K&SqMF_9f@ig`^yRNSSQ|#;^kvHZ>MmE%idAKE9&9rzEFQQ#;>eAdcL|4! zd0Th=%1yX7^G57|%Vv=o9T_~E%+VB;Ak91bT)5hSV49sbFZx7 z^U?A?Rrt43-``lq((XOifm+)u484}b|J6iID1_uAmJiIuj!@%!LW-yDEfisyhe{lx z*_Yv5b`ePaa4LR$7U)z-a&KA21iYS%iGq!9M-u~j7X3#m0QhQD;>2A_hj|+>;kRP> zotm%cA+8*M#8gqAduC)FBAQU5+(q_|qeG&=3?pDT#aYpf@I#Jk;@?LXFC^nPXB`2~C4HZm3J_iIAw363~$QzlqU}w$Y+?|9{C5}GoPrk?HT90EL z6DQ@^UVz`F_7#;AMfv=!14ek_aI=T*o2P=?y1CCk+7+uGcIeqB_@vJcf`zhf9XC8Y9ns-zYjM0&di(C=9C5JqRQ7}0plZn+f=mAyV<+H9@)5^PiR z+Q6edU1p?uUd%<}+4gRul~L`jg~3w+#nx3a+)b8_uZDT4WS^%DP-prIIQM7H82jLV zkk{&i{aF*!D)kS+iHdhsr+0=AlVsTu4=I$?GB-AVeA|`yM>;f^JdJDz&rIQtxK#Sl z_IyH0W+}|dAW_*{f#^w-x8Y>7S2aw1ExG$}7N7mnx0x225=;F3Rl52OjMMnYE!dfu zw`Xsli`La34ex4H0X^DK zVz0<}c57vfXAg|t|Dak+x0K9p7bizIg8Xnm3YEP6%FNkL`s?S=?C12StI3miYHlc6 zT{x>U#n)Bur$0IK)c%faPVcfnjV* zQ>@}U|KGGu5W2>6KU5fh2911XkGzku{@G`timj_MpG<}G9;@m4;nkq<-A`mJ-_yF> zH@X-}kP!yJPOh7^cCBw)TpE5vAkzhnH)uF*-q{M>QDD*j)ixICAYVi)(~pSJ-UAXsVbT*NQEj_#4%YUaN+}JudbpICah%DXxwg=Qb(XP3{Zt_O z<>FIr$gV1mf3;u8P8U=y3aYeK2NchEII~wWi`)Qj**6}LW8Oy>hOP&H;WhR)!9zRO z=d4Hqj$aS8JBwuD)!T-sPYUC^Pm;YdDQwvHihOvh@Ms`IDfn^+PW~Xl`;VOA?*Lg_ zkvZlx4?^(tD?e0+w7{d!Y^RRt*-7~BVAl0CamJ5p{Lx$V<3IhC^-oUNuS(-n5R9BghPObl9VG%WJz*sJm; vQ>#s@%G3iMrzpqwU^h)Ha{Gvuv)RMKahGuGPrFBz|!5_ zvE*~lJNMl0r)%b%GxIywbv_*w-xwboG>lpY2OIYvAp{ZfMyW_Lgc`9Q&7y8)Y?O zY$T|(^wLH|Ca1@P6*JP;VcvJBJ%xYmca~hIR;7#2`*n^O%p4QME z;|smkY`wqzjj~nQR(9azL~O|i|DnaiL=vSq0iP&zAat68e(HzwTUJE|FI0{%4&; z`seKV|FaSjMoE(*q)P8&c7Rm&0K+C7v}Cx)?}5DMIkbU z7B%vfADeg&df;m?C6=^d|KxbTZVTm);+qN%$%szM%Rg-5U*RV2ms^~|+Is7~gYL>=ZMl(#p zvu`KAzw^UPP#tKX`F=9YL*F>is9oE+YHU?yhx{4!p7nY#ZydWTB<`rf@e7%UuWkN! zpM#Ag9{HUD_pgXTp6rKq6)kZ0Z)(OiHR>TQCp^jc-kF`8op}Dbr<@;qh z!Agv;O?iN3O9|wosjcLvI&vT~O=uUG8MgVHCEUGB{jq2$J||4CL0CE08yOP&R+#Go^vXj5zjiqIJVnpRcpc9I*BB=aA9W;#-UGyf1gm$C zvm-dLe1=&WT^&Zxa zW|*>q>F&`2#@yg@kGxR@Io#TSQ+MtSk+WMiGU=n%K(-)89gSBrAB}b=YpEz)Nu-{< zGFi?h31|xrbbbb&3&`+Yc|mvRarOW&5vWNse_JLGmsn}T8eENb1qDy@olRk1l5xaa zyo@=>h3c+~Np;EB&IviwwDRp_q^o=}u|MP0$vh)k%F)Y1wGKAZQPN-kT1Pp=^YBj% zmN#S$Qr7Chrx)XhcV1GD)q0%@lS{WO%XCFFjLkgrE9Tv{+h+)XI0)V(t2#z&03rts z^=#kb50c1j%e+MvoQaCUsMxDTGbs*l@cR6!ZC^xHv6XfU=i_qGEsQPXnH2clFAbqb zD9$JKsGW2DZt04!acN0cBD0h}QE&@pTQ6o)RVRBKk;FsU8ek#~>V0KIr}Z zvf4gw*t*(MQ%g}@xw-w`w>-lX7^H_+;!WLkZN0S2ZCv{cCUS~6PSTSv9$8cv^DUC0 zYS~yp8KmlTvmCC<=_*|mB@k-!Xkj&nmcNfB@CG8y4qGcKaTN7hrQpi=cZ-5{=9OSKn~OVp;4>NNU$&k-?y0*1>0oNR6eQ!SVQOv@@;*S zPop09P|m2!Agr&8XH7~pi)Q+dCJ(db>h(R?+8!_Ddnr2Dw)VgGi)5qi{qZf$lAeT_ zl>N$>*kh!=%oG|aCw18XmJl}QG*cV<<^Kb+hev(fQ#Y-%l2uFx_W49sSiav```9WE~T==JlvQqRgk+F)EqG>65 zF@Sx0>_LAcquFHT+zPw#Hod%%WP9DSre8Q8i9UXr16*+NIB^!g4WjJLrB;u61MXcj z;~AgnnV>8M3l1HcjEQg;+x~p0wW(=B=68sA2GQx>k`1i+TO)ta0vXOpq}G>N{)+9m zh=tYq;hW7rh`ZAU-9Z!MTW`~G|KF4F$hD6^PX`kng0ad@-074|7PZmB+C6vBm7Df{ zL1ND=1`@1INPPQgg5Y@upXiJci6T4reFb^S1{r^bJ*~v!>!R#5+0=z5dKsbmPdM?2 zhzAnrT&6!(*fVwv04>IXsF1m}X3Ms4FH`nrMIP)W*eJmrRN$haUV%fgXh>D@QH=Xi zI*K!uqokC=ETUAex1t_wmlID~>kHhMF~R(1+$kXCmkiD0Y3Pu*o792y*4mxn-<}b}WK^um-=}#E4baOlc(JePN948$vj2*%fejN>SDxBox20 zn_lJrR%4~|l#I|QGDxsFQh_$rh0$D;ykd5u6iSl;@a|lu-2ZtQGBvZ=%hJp(_aqg3 z@B%3YNg=OyFmo+$5O~MJg5+kavHc#hfJMKM4cg(fcuQY;{Nw)694^VL{VCZ4 z)zI3DuQ9}ZJ3o8x%m+|v+xyX+5zee_#Vr4IU^CupOjOAnlC$3Xr5h%@E6K46r%TwK zcD@7TeJ)+=SX9v4q`M4*q$d+O0@4B@dxbj@SJ^5P;dK$V!>J#agE*~bl^bd!B?GFs z%-os?s1u8eoHiO>>ID_H^CfB<1u>vp@b4Xi+nyLi-i;21tl#FTk}WUNz^4Qeg)zq} zPa`a^Zm|?iZ11|cR$tBeonMOltbOaZrS}IA+B!9ScKvyF0Q!JC&YH#z!dg`kUe3WO zVBye)q^<`mEmA!%nIR#@8d;M-N2#$eCFadi5!iz3guSQ%| z-t0(}W%J5J{iy#WHgu;M(kXmX(DK-eCS^1{SWauj37tp*-}~*(sWObv&@b)_#oz+` z<0eEEhBiInS=(!rzWVrw*Ts|F{Z3;W8-$SsM7O13!*$`3gyG!L9XfUX*Iy3y?r@Y; z4i*%s^&7FV4D)o+B$k80JA~!c+FVS@T{}{C+x@6qYGX^4W5W%hLG-tL!4Ios&25~@8UusDr`M%5$&aky)=W&Ud)VDhDo#^U z1;9-g0?hlEERfxMsk=u^kny!fw?_u%A>}*MySqqo%w`9FQkvd?)&vGJ4HT>1H!#|M zXHww;8A@dH4aa)xH|2E=P1W@`PY8nRS10lbxR+xK4LRSxNuz^OntFv3&tN)X7McDL zC;kGY6jv?X8To^|dzw^@rE`iS1O)u#@@6eHx#gepYd=P`<(Utm=oGX3ack zSt_kki6E~)a9XKVt&bjRBJX&cG$K`bjl^Y^b?3@!bog79K9ZlYY4A0}LR2(3u*-9- z{i-*Ssk35g4kmPFK9uWFnW;5xj|U$+eOqyy)J4jqJbs%cP8S%;0E>J2b1bvn=H`}j zpHImB=|$SI5R}`cpfQ5o#Sn!Po-dTbRAdI?kxCYNrk?yIX}2!u;@Q3Xfo08Ei)jk0 zm2^GLS08jjYx1P;bO3K-h4_*UahT|omvrGA_uTQs=JsTIrlQkqPxN2zi!NIynUd9x zSW-*>n!XhsCGChH>-a4Qi!N3)YZ9bwiMsPuIB4adXep$xl&`EWb{rQsL2<$ z=c3JvtWvU(4p6oxQ>))qxJ>Pg9#=5rRgd;iqsM;ZWF{yDNNcW@7YE1IUW#UU1UIZ~ zHI8xn32jb}5J*zi}Kz5H7|o2PqTd@z+MSwr*t>qtGWDKGM%JJ=h7B zg@+U2_qxa`8==@p@j;|pW{zLO9~QRO!pOe*&WXVMopO--iF0@|vyD)56&B!` z5VOQqGA0WYL(ASm(7+_ok*llwaHW(;eUgtsIh_1Br=u;Rf^$WvL-RHv-;AlbnS=Jg zOw|?~LyKr{0<~93ZZkM6UfUK zUiGP;Zc>^9ana}&=Z|zvJC&cyH#QvC^62&z9s`A+7e4%6aDNLnPI3L2N^wAFhZ6oM6=wPZvyZtyIfJ<5tw`v#U_njWVg!D~<< z1|a>06nK#wY0I5#Ve^L6+_h9xDe4_~g&HqDF>=&h(RtUGZ0z7)2aGy-&hO0S;Vb<3 z85vsS;izzWwjtLkMYa`&)p&n@r}n{Zi|o~bjyDCUppO_tR>Vdy@f&5Dx!WxUZ|8?} z^B*`@QMXUexCR=KbZflP>88oL-d|iM2e9>$2sj_yb;bA{D7O2c75ms|C|Lfu(9Lja zcxkqi%kbJ6C57Jw?*`7idGy(_(DCfGi9B4`KvpxdM7`-$fwT0sVD7Eh6a^Jz`)WJ3 z*3Yl9h8I~HY!J@-Tw=|8{havX^v&coG>%GKV(hh-D!|GG z{3&FtSid5puxUG&5IZ1uuZsF%RvfK2Qg2w_T#EF@+E%Qbem(gc3V!kRhZgq0Qk#a5nE># zlTpGv(@s(A*u?(19UT{Yf3WO}TGC4-%4&7kGihGkS{~)ed$YQTwnmonvwhu>s8wGV z*yJ!75yBAcX4K5{DdO^RGM8skAT7S+$6D1DD|*L{S;a4~#8uih&Zauiif@JAxxC4M z&K1M8b)uO}Y0}yKXPZI20R6-5N+(_CT90bFmX@OEEg^)}Cw~mdAUqNgbGI;~1PC+GG31=Jp3F}m>g`S+j-;Jw@$$F#B z6PWE5OS=t~BCfi%yuh4>$$0p*qnIR5Eb!Aj_r0Wb(8G0C<^5qud0XidwApd2jLBrBG54hdvpW_cjsdNTv$ zfZ~%|$Hw)NG+!J6ROlpM$lubeM}aMlQ?|CKC|SLx$IcO^x8N5nz03z;ar7rsV&#-6 z<`KA=6fzPF4~JYl&o5AuuRjKIaw^MFcV}7m%JaX9f0VU>NNQ$2Q^9Hhr5zi9bA|VP zj^INRj!jCW0b1#s6M}n}AL4P5)4v{m>-1+P5e_HJS3|i0)M~qpLO5ueW9uO6%DsIV zOyn@8_a6HqWi7GN+03{T%U!RY`Fg{kK?Cxwe8G6xj^b0lbY|@ z&r=+gTw?T8IVcR0c6mJ^U!{f7#WqhY2<}s&6LJpTh{wgwXkpcQ)r?w(1RqZy@oDM+ z>I1EI`jX@5Px|s0_1qHsQvNJgDK7ZhE$gG~%ZoQb{YQDc?G~+2X(%g{5QP7P6c>jM z9}ABvLaevF^ah--|CpBLC>`PAGr~HLN97)-C186HY(p5F)V*!Y7gRKM+lPaT9hLV# Dh68^s diff --git a/common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh b/common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh index fd07df3feb..767e79016b 100755 --- a/common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh +++ b/common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh @@ -16,6 +16,9 @@ # # source the properties: +script_dir=$(dirname $0) +echo "script_dir: $script_dir" +cd $script_dir . ./lwM2M_keygen.properties # Generation of the keystore. diff --git a/common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_keygen.properties b/common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_keygen.properties index 8dd2c30a9a..27e5fa57c7 100644 --- a/common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_keygen.properties +++ b/common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_keygen.properties @@ -43,7 +43,7 @@ CLIENT_STORE=clientKeyStore.jks CLIENT_STORE_PWD=client_ks_password CLIENT_ALIAS=client #CLIENT_CN=client_lwm2m_x509 -CLIENT_CN=mobile_lwm2m_x509 +CLIENT_CN=LwX50900000000 CLIENT_SELF_ALIAS=client_self_signed CLIENT_SELF_CN="$DOMAIN_SUFFIX client LwM2M self-signed" diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigBootstrap.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigBootstrap.java index c8215b7ef3..286f555c0c 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigBootstrap.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigBootstrap.java @@ -24,7 +24,6 @@ import org.springframework.stereotype.Component; import org.thingsboard.server.gen.transport.TransportProtos; import java.security.PublicKey; -import java.security.cert.X509Certificate; import java.util.Map; @Slf4j @@ -104,10 +103,6 @@ public class LwM2MTransportConfigBootstrap { @Value("${transport.lwm2m.bootstrap.secure.alias:}") private String bootstrapAlias; - @Getter - @Setter - private X509Certificate bootstrapCertificate; - @Getter @Setter private Map sessions; diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigServer.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigServer.java index e5643a90f2..9d3e199aea 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigServer.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigServer.java @@ -233,7 +233,7 @@ public class LwM2MTransportConfigServer { } else { log.error(" [{}] Read Models", path.getAbsoluteFile()); } - getInKeyStore(); + this.getInKeyStore(); } private File getPathModels() { diff --git a/transport/lwm2m/src/main/data/credentials/serverKeyStore.jks b/transport/lwm2m/src/main/data/credentials/serverKeyStore.jks index b5b6c9fa3c43118262f4c89b1ba319ef09b694d0..e1d6deff4b3fd948655f802da4ad65f0ba568f4a 100644 GIT binary patch delta 5500 zcmYM2Wl+=&*T!jBSV}sSl;&oa5|9p+ZjtU@Lb~J+OCuq|QqtYsu}F7FH-dn4E+q)> zJ?}j8JfE(a>ztY2IoJ7iW_iYVm?3b=cNplH{|Y(|h%5YE_zfXCE_x1};sOg!aRPx; z93(KySOyFXE^HOWag!{fQfkM{^n$cphcPhGdNr`#Wt>Q!PDa6mlL-fIR>V+JVL!8t z6X=^CxJmuvKUmO}t4=wD7icL2NvU3iy9#}u2|GX)yjJJ&myU34J;XRUYa_+b3b;ls zCJYD@3qv77La!iDC_j`R5@yYLQt^XkGc~Lo7};0m1nX`Ph<+;prApPQ&uuKCeeY#=-v#&G!-tyqzja z?PT-IcbtWaL_!eim5B-H;^6jgHUM*-G4I&kwb}IfYIF1tkK-iywDN@F=&DR&GZTifsnouggpyc{<&+3#<$DKD#OS`{%gzII<^|pUAg$=My$RP+=yDd3093CqiMN>a7JG7N!Z>bElZk_I`x8f)- z<(&QL?UUDOcA<70GZc7dmyx;QPYMbIU*AWvrl$SM^8k2TN(&6&0@`XKmvFLP0(-@Dkmu?=y+Vo5t%POsjw_UayDi|^4A(xHT zWSrwk=y5|_OhsP}P8n{wj8zmRQW2kDN`@H0q-CI1_R36?Z&FTod*j4Q2@W=~I|J_Z zG#pI;jmh_EuWq)~R`T&Ec(-ZpJOvY?6OI#qN}VINH(dL|pqgKb zEjT*BO8y?mCY*Sa%ZZipIz-}#XUezsw6{Wh+BAxdn4tbV)fV=-vG)ZRCLq@}NwZUl z;y5X5Z^aJA=8n#sD=hq?tdaN_dvX6*b!`}+Q&JgJ8Gh7#P{4!-G*z99v~B8W;4S@eU5`aG>T#I zRLr?5Nd<-g(fXtCLPBIpns}A<Iw4B{4zIU#XvF$-^V6d3C=@@OJ$1i`ztU*=+J;1rKN{v1$nkC`xOShrf5FGf5jv z7ZJ)@!%t>dj7GaGTIGpKXcU}dvfG8pd;lwzAl{G#QqG>IRuwyE;{{DjO3BT`Z#}#G zC5KeU`w=BZ*JonpU>=x^@|YC!I7 z@pzOMc)nSq(<{HN$%pk56@{s`B{W7z!y9u!(U=+b22(#4tPSK@O^J&xEC%OUv+F3vo zbo@l*?CI}tEQU?r^QQy&x2iY7; z|I)xS1*sl}RrQ4jXr#>>;v0RO=L`xd1#LxNTD6}gfhQg=F|-R`Si8OLs?e7?7z=0j z7+PFWfKU7GRHdAmeq-zlChfl4czLfuK01DD_{PO1h6m4c`Wd4gEC3FTkD~s)O+~|Hmv+^v7?gcXW(k+#$=0yE~pvhUNBHXPbOTM?GA z_sOZQ^`aNVtbDVTBT*b@jz+VP29)6p^g`p!E&b=5Bvm$}@x z>gDWT4cT#eGIJz>=!C{x!Rv0FVIm)NNbHIaZ>)ar5I{wWpL*tT{7{+El|kZl$5O*C zKfrf!i3prV+S1iyA*K^mj6d1!;_e~mq%}wtS1`Euc!vXxB12|_RXP zHj9Pv-Zzn24aR;4cf3m`F)L}}Zw1|GwbqYV_@nt(tM__;512+xZ7NM-4jE@v?sfMR zYBth(0^RA4-tB?BPvDdm9B70b{;pxq6aK=B=W4O+{4d??pK=>)AeY`t_h0(x>2yk? zS6x<9_eI~?5~|4c$svli{c|@x5V-l3luJIwkk3j!e;m;Q#CY8q9shX{BB?7;bMr_( z4*%w%D*a-cj1m0BKw1E>QRUQjSM$h~*+y<(77OckpXTxEQU^oO7fJi0HV3ZbM5N@vvIB_(!u$HhGz59mF zNUcOx6hbymgg1aeXgD`d9ilvIuAkzka=T3RTly7($P%GF^**l3gI*!h^zB=YMp@m3 z`3RAZP$>d`d$c|=E7tK0@WLc-N%+$maQ!g08T9Cm-NO5~X*8;HsqP-eEP^Y9qQNx# zJl0cgJIOyBNvVz1_4g};A}?V?AHHubc`kE(KzgLRkpAkm^aEZ(G3=gYU%!UiaS z{3|m5zY@IL&}^@%VK?@8IGeVYHC28U2T|C@epdHphg|I> z#4{1O(Duj=RS_osXsAy0L;Xq;bhPA4B0eoV-FEY0sEyQ2+t%*8H(n3`HHN_L3TY@H zNGaAk`87peDoAYwIS6U8&v!w@u^6RZ-^`7BF>@*&Qw}pu%4;fPFMO@#q@Jhx9f|C9 z#@NN4kDa0Wlq#>Knt~P6l;uKRQy>L8n$pzZ&zJA66;QSPiaZN6N{6#aBOSFEGd~K3 zRLTDKO~Qqp?@R&C$R_|}c{p2piAqGrzu97xM4Zz;j;A#USrRfVz+o~h9738J2Ks%K zaxLyS#gg=uBl~bdel&}zQ94GWf`6fItTchGm8l%OiG_C3KPGf)_m8`fs-hhIiRw_y z>fU&fduMCUC{n>Q+6`WCCd^!)LB7FlM8b+A7VT0BxXT-YRRHCYVERdULy8wcxV$-n z+mcf|a}^&V>~=R?lDaQn-Ofd!r|A^T!`gk%3iE%^><>x5COx6GzNS6~=_w@ycHF<+ zUyfPx389@nqAE;Wen}G4ym?%V)s^4hTGOnO zf`=@*9#&QN%>aK?K`XaEKdl$06iD`iM8bNuv;;LSuFaat%w5I$@%kDn7*2zWD7}12 zw^;0B?pO!%esOrSQreF3ef=^@u%8+GRc`wYw7Oz}rx5Rc-4>{eu)hoyC$rl#;+Pwf zCC?r6W#k%V^@7<}V$K#2YcSqi=MYiW{Mc-cCHa@S579e5!%ax{EybyhpdcpVj^~I&k z){h3fR@d(P* z6h(|M^Aqj|Y?@XLr`aNM`6qh1g?#+T)t=^|!!GxbC9nF6qk?*(JgJY|sV!Ds!Tbi& zJ9@we!vl6@@IF~&U*tJDd%K&SqMF_9f@ig`^yRNSSQ|#;^kvHZ>MmE%idAKE9&9rzEFQQ#;>eAdcL|4! zd0Th=%1yX7^G57|%Vv=o9T_~E%+VB;Ak91bT)5hSV49sbFZx7 z^U?A?Rrt43-``lq((XOifm+)u484}b|J6iID1_uAmJiIuj!@%!LW-yDEfisyhe{lx z*_Yv5b`ePaa4LR$7U)z-a&KA21iYS%iGq!9M-u~j7X3#m0QhQD;>2A_hj|+>;kRP> zotm%cA+8*M#8gqAduC)FBAQU5+(q_|qeG&=3?pDT#aYpf@I#Jk;@?LXFC^nPXB`2~C4HZm3J_iIAw363~$QzlqU}w$Y+?|9{C5}GoPrk?HT90EL z6DQ@^UVz`F_7#;AMfv=!14ek_aI=T*o2P=?y1CCk+7+uGcIeqB_@vJcf`zhf9XC8Y9ns-zYjM0&di(C=9C5JqRQ7}0plZn+f=mAyV<+H9@)5^PiR z+Q6edU1p?uUd%<}+4gRul~L`jg~3w+#nx3a+)b8_uZDT4WS^%DP-prIIQM7H82jLV zkk{&i{aF*!D)kS+iHdhsr+0=AlVsTu4=I$?GB-AVeA|`yM>;f^JdJDz&rIQtxK#Sl z_IyH0W+}|dAW_*{f#^w-x8Y>7S2aw1ExG$}7N7mnx0x225=;F3Rl52OjMMnYE!dfu zw`Xsli`La34ex4H0X^DK zVz0<}c57vfXAg|t|Dak+x0K9p7bizIg8Xnm3YEP6%FNkL`s?S=?C12StI3miYHlc6 zT{x>U#n)Bur$0IK)c%faPVcfnjV* zQ>@}U|KGGu5W2>6KU5fh2911XkGzku{@G`timj_MpG<}G9;@m4;nkq<-A`mJ-_yF> zH@X-}kP!yJPOh7^cCBw)TpE5vAkzhnH)uF*-q{M>QDD*j)ixICAYVi)(~pSJ-UAXsVbT*NQEj_#4%YUaN+}JudbpICah%DXxwg=Qb(XP3{Zt_O z<>FIr$gV1mf3;u8P8U=y3aYeK2NchEII~wWi`)Qj**6}LW8Oy>hOP&H;WhR)!9zRO z=d4Hqj$aS8JBwuD)!T-sPYUC^Pm;YdDQwvHihOvh@Ms`IDfn^+PW~Xl`;VOA?*Lg_ zkvZlx4?^(tD?e0+w7{d!Y^RRt*-7~BVAl0CamJ5p{Lx$V<3IhC^-oUNuS(-n5R9BghPObl9VG%WJz*sJm; vQ>#s@%G3iMrzpqwU^h)Ha{Gvuv)RMKahGuGPrFBz|!5_ zvE*~lJNMl0r)%b%GxIywbv_*w-xwboG>lpY2OIYvAp{ZfMyW_Lgc`9Q&7y8)Y?O zY$T|(^wLH|Ca1@P6*JP;VcvJBJ%xYmca~hIR;7#2`*n^O%p4QME z;|smkY`wqzjj~nQR(9azL~O|i|DnaiL=vSq0iP&zAat68e(HzwTUJE|FI0{%4&; z`seKV|FaSjMoE(*q)P8&c7Rm&0K+C7v}Cx)?}5DMIkbU z7B%vfADeg&df;m?C6=^d|KxbTZVTm);+qN%$%szM%Rg-5U*RV2ms^~|+Is7~gYL>=ZMl(#p zvu`KAzw^UPP#tKX`F=9YL*F>is9oE+YHU?yhx{4!p7nY#ZydWTB<`rf@e7%UuWkN! zpM#Ag9{HUD_pgXTp6rKq6)kZ0Z)(OiHR>TQCp^jc-kF`8op}Dbr<@;qh z!Agv;O?iN3O9|wosjcLvI&vT~O=uUG8MgVHCEUGB{jq2$J||4CL0CE08yOP&R+#Go^vXj5zjiqIJVnpRcpc9I*BB=aA9W;#-UGyf1gm$C zvm-dLe1=&WT^&Zxa zW|*>q>F&`2#@yg@kGxR@Io#TSQ+MtSk+WMiGU=n%K(-)89gSBrAB}b=YpEz)Nu-{< zGFi?h31|xrbbbb&3&`+Yc|mvRarOW&5vWNse_JLGmsn}T8eENb1qDy@olRk1l5xaa zyo@=>h3c+~Np;EB&IviwwDRp_q^o=}u|MP0$vh)k%F)Y1wGKAZQPN-kT1Pp=^YBj% zmN#S$Qr7Chrx)XhcV1GD)q0%@lS{WO%XCFFjLkgrE9Tv{+h+)XI0)V(t2#z&03rts z^=#kb50c1j%e+MvoQaCUsMxDTGbs*l@cR6!ZC^xHv6XfU=i_qGEsQPXnH2clFAbqb zD9$JKsGW2DZt04!acN0cBD0h}QE&@pTQ6o)RVRBKk;FsU8ek#~>V0KIr}Z zvf4gw*t*(MQ%g}@xw-w`w>-lX7^H_+;!WLkZN0S2ZCv{cCUS~6PSTSv9$8cv^DUC0 zYS~yp8KmlTvmCC<=_*|mB@k-!Xkj&nmcNfB@CG8y4qGcKaTN7hrQpi=cZ-5{=9OSKn~OVp;4>NNU$&k-?y0*1>0oNR6eQ!SVQOv@@;*S zPop09P|m2!Agr&8XH7~pi)Q+dCJ(db>h(R?+8!_Ddnr2Dw)VgGi)5qi{qZf$lAeT_ zl>N$>*kh!=%oG|aCw18XmJl}QG*cV<<^Kb+hev(fQ#Y-%l2uFx_W49sSiav```9WE~T==JlvQqRgk+F)EqG>65 zF@Sx0>_LAcquFHT+zPw#Hod%%WP9DSre8Q8i9UXr16*+NIB^!g4WjJLrB;u61MXcj z;~AgnnV>8M3l1HcjEQg;+x~p0wW(=B=68sA2GQx>k`1i+TO)ta0vXOpq}G>N{)+9m zh=tYq;hW7rh`ZAU-9Z!MTW`~G|KF4F$hD6^PX`kng0ad@-074|7PZmB+C6vBm7Df{ zL1ND=1`@1INPPQgg5Y@upXiJci6T4reFb^S1{r^bJ*~v!>!R#5+0=z5dKsbmPdM?2 zhzAnrT&6!(*fVwv04>IXsF1m}X3Ms4FH`nrMIP)W*eJmrRN$haUV%fgXh>D@QH=Xi zI*K!uqokC=ETUAex1t_wmlID~>kHhMF~R(1+$kXCmkiD0Y3Pu*o792y*4mxn-<}b}WK^um-=}#E4baOlc(JePN948$vj2*%fejN>SDxBox20 zn_lJrR%4~|l#I|QGDxsFQh_$rh0$D;ykd5u6iSl;@a|lu-2ZtQGBvZ=%hJp(_aqg3 z@B%3YNg=OyFmo+$5O~MJg5+kavHc#hfJMKM4cg(fcuQY;{Nw)694^VL{VCZ4 z)zI3DuQ9}ZJ3o8x%m+|v+xyX+5zee_#Vr4IU^CupOjOAnlC$3Xr5h%@E6K46r%TwK zcD@7TeJ)+=SX9v4q`M4*q$d+O0@4B@dxbj@SJ^5P;dK$V!>J#agE*~bl^bd!B?GFs z%-os?s1u8eoHiO>>ID_H^CfB<1u>vp@b4Xi+nyLi-i;21tl#FTk}WUNz^4Qeg)zq} zPa`a^Zm|?iZ11|cR$tBeonMOltbOaZrS}IA+B!9ScKvyF0Q!JC&YH#z!dg`kUe3WO zVBye)q^<`mEmA!%nIR#@8d;M-N2#$eCFadi5!iz3guSQ%| z-t0(}W%J5J{iy#WHgu;M(kXmX(DK-eCS^1{SWauj37tp*-}~*(sWObv&@b)_#oz+` z<0eEEhBiInS=(!rzWVrw*Ts|F{Z3;W8-$SsM7O13!*$`3gyG!L9XfUX*Iy3y?r@Y; z4i*%s^&7FV4D)o+B$k80JA~!c+FVS@T{}{C+x@6qYGX^4W5W%hLG-tL!4Ios&25~@8UusDr`M%5$&aky)=W&Ud)VDhDo#^U z1;9-g0?hlEERfxMsk=u^kny!fw?_u%A>}*MySqqo%w`9FQkvd?)&vGJ4HT>1H!#|M zXHww;8A@dH4aa)xH|2E=P1W@`PY8nRS10lbxR+xK4LRSxNuz^OntFv3&tN)X7McDL zC;kGY6jv?X8To^|dzw^@rE`iS1O)u#@@6eHx#gepYd=P`<(Utm=oGX3ack zSt_kki6E~)a9XKVt&bjRBJX&cG$K`bjl^Y^b?3@!bog79K9ZlYY4A0}LR2(3u*-9- z{i-*Ssk35g4kmPFK9uWFnW;5xj|U$+eOqyy)J4jqJbs%cP8S%;0E>J2b1bvn=H`}j zpHImB=|$SI5R}`cpfQ5o#Sn!Po-dTbRAdI?kxCYNrk?yIX}2!u;@Q3Xfo08Ei)jk0 zm2^GLS08jjYx1P;bO3K-h4_*UahT|omvrGA_uTQs=JsTIrlQkqPxN2zi!NIynUd9x zSW-*>n!XhsCGChH>-a4Qi!N3)YZ9bwiMsPuIB4adXep$xl&`EWb{rQsL2<$ z=c3JvtWvU(4p6oxQ>))qxJ>Pg9#=5rRgd;iqsM;ZWF{yDNNcW@7YE1IUW#UU1UIZ~ zHI8xn32jb}5J*zi}Kz5H7|o2PqTd@z+MSwr*t>qtGWDKGM%JJ=h7B zg@+U2_qxa`8==@p@j;|pW{zLO9~QRO!pOe*&WXVMopO--iF0@|vyD)56&B!` z5VOQqGA0WYL(ASm(7+_ok*llwaHW(;eUgtsIh_1Br=u;Rf^$WvL-RHv-;AlbnS=Jg zOw|?~LyKr{0<~93ZZkM6UfUK zUiGP;Zc>^9ana}&=Z|zvJC&cyH#QvC^62&z9s`A+7e4%6aDNLnPI3L2N^wAFhZ6oM6=wPZvyZtyIfJ<5tw`v#U_njWVg!D~<< z1|a>06nK#wY0I5#Ve^L6+_h9xDe4_~g&HqDF>=&h(RtUGZ0z7)2aGy-&hO0S;Vb<3 z85vsS;izzWwjtLkMYa`&)p&n@r}n{Zi|o~bjyDCUppO_tR>Vdy@f&5Dx!WxUZ|8?} z^B*`@QMXUexCR=KbZflP>88oL-d|iM2e9>$2sj_yb;bA{D7O2c75ms|C|Lfu(9Lja zcxkqi%kbJ6C57Jw?*`7idGy(_(DCfGi9B4`KvpxdM7`-$fwT0sVD7Eh6a^Jz`)WJ3 z*3Yl9h8I~HY!J@-Tw=|8{havX^v&coG>%GKV(hh-D!|GG z{3&FtSid5puxUG&5IZ1uuZsF%RvfK2Qg2w_T#EF@+E%Qbem(gc3V!kRhZgq0Qk#a5nE># zlTpGv(@s(A*u?(19UT{Yf3WO}TGC4-%4&7kGihGkS{~)ed$YQTwnmonvwhu>s8wGV z*yJ!75yBAcX4K5{DdO^RGM8skAT7S+$6D1DD|*L{S;a4~#8uih&Zauiif@JAxxC4M z&K1M8b)uO}Y0}yKXPZI20R6-5N+(_CT90bFmX@OEEg^)}Cw~mdAUqNgbGI;~1PC+GG31=Jp3F}m>g`S+j-;Jw@$$F#B z6PWE5OS=t~BCfi%yuh4>$$0p*qnIR5Eb!Aj_r0Wb(8G0C<^5qud0XidwApd2jLBrBG54hdvpW_cjsdNTv$ zfZ~%|$Hw)NG+!J6ROlpM$lubeM}aMlQ?|CKC|SLx$IcO^x8N5nz03z;ar7rsV&#-6 z<`KA=6fzPF4~JYl&o5AuuRjKIaw^MFcV}7m%JaX9f0VU>NNQ$2Q^9Hhr5zi9bA|VP zj^INRj!jCW0b1#s6M}n}AL4P5)4v{m>-1+P5e_HJS3|i0)M~qpLO5ueW9uO6%DsIV zOyn@8_a6HqWi7GN+03{T%U!RY`Fg{kK?Cxwe8G6xj^b0lbY|@ z&r=+gTw?T8IVcR0c6mJ^U!{f7#WqhY2<}s&6LJpTh{wgwXkpcQ)r?w(1RqZy@oDM+ z>I1EI`jX@5Px|s0_1qHsQvNJgDK7ZhE$gG~%ZoQb{YQDc?G~+2X(%g{5QP7P6c>jM z9}ABvLaevF^ah--|CpBLC>`PAGr~HLN97)-C186HY(p5F)V*!Y7gRKM+lPaT9hLV# Dh68^s diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts index 9f1fed9bc9..c5d56aa85a 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts @@ -36,7 +36,7 @@ import { import { Store } from "@ngrx/store"; import { AppState } from "@core/core.state"; import { coerceBooleanProperty } from "@angular/cdk/coercion"; -import { WINDOW } from "../../../../../../core/services/window.service"; +import { WINDOW } from "@core/services/window.service"; import { pairwise, startWith } from 'rxjs/operators'; import { DeviceProfileService } from '@core/http/device-profile.service'; diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts index d724a25332..2cc6fe819e 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts @@ -35,9 +35,9 @@ import { TELEMETRY, ObjectLwM2M, getDefaultProfileConfig, KEY_NAME, Instance } from "./profile-config.models"; -import { DeviceProfileService } from "../../../../../../core/http/device-profile.service"; -import { deepClone, isUndefined } from "../../../../../../core/utils"; -import { WINDOW } from "../../../../../../core/services/window.service"; +import { DeviceProfileService } from "@core/http/device-profile.service"; +import { deepClone, isUndefined } from "@core/utils"; +import { WINDOW } from "@core/services/window.service"; import { JsonObject } from '@angular/compiler-cli/ngcc/src/packages/entry_point'; import { isNotNullOrUndefined } from 'codelyzer/util/isNotNullOrUndefined'; diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.ts index 31ab078485..44d9066440 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.ts @@ -30,14 +30,14 @@ import { } from "@angular/forms"; import { coerceBooleanProperty } from "@angular/cdk/coercion"; import { Store } from "@ngrx/store"; -import { AppState } from "../../../../../../core/core.state"; +import { AppState } from "@core/core.state"; import { MatChipList } from '@angular/material/chips'; import { INSTANCES_ID_VALUE_MAX, INSTANCES_ID_VALUE_MIN } from "./profile-config.models"; import { TranslateService } from "@ngx-translate/core"; -import { DeviceProfileService } from "../../../../../../core/http/device-profile.service"; +import { DeviceProfileService } from "@core/http/device-profile.service"; @Component({ selector: 'tb-profile-lwm2m-object-add-instances-list', diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts index b0f9ea4ebf..bf9570f95c 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts @@ -32,16 +32,16 @@ import { } from "@angular/forms"; import {coerceBooleanProperty} from "@angular/cdk/coercion"; import {Store} from "@ngrx/store"; -import {AppState} from "../../../../../../core/core.state"; +import {AppState} from "@core/core.state"; import {MatChipList} from '@angular/material/chips'; import {MatAutocomplete} from "@angular/material/autocomplete"; import {Observable} from "rxjs"; import {filter, map, mergeMap, share, tap} from 'rxjs/operators'; import {ObjectLwM2M} from "./profile-config.models"; import {TranslateService} from "@ngx-translate/core"; -import {DeviceProfileService} from "../../../../../../core/http/device-profile.service"; -import {PageLink} from "../../../../../../shared/models/page/page-link"; -import {Direction} from "../../../../../../shared/models/page/sort-order"; +import {DeviceProfileService} from "@core/http/device-profile.service"; +import {PageLink} from "@shared/models/page/page-link"; +import {Direction} from "@shared/models/page/sort-order"; @Component({ selector: 'tb-profile-lwm2m-object-list', From 33a900145cba25066632d0bb4f8cbf977392269b Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Thu, 14 Jan 2021 19:24:19 +0200 Subject: [PATCH 029/249] Lwm2m: back: created sh with many certX509 --- .../credentials/shell/lwM2M_credentials.sh | 308 ++++++++++--- .../credentials/shell/lwM2M_keygen.properties | 19 +- .../credentials/shell/lwM2M_credentials.sh | 403 ++++++++++++++++++ .../credentials/shell/lwM2M_keygen.properties | 57 +++ .../LwM2M_BinaryAppDataContainer-v1_0_1.xml | 17 - 5 files changed, 719 insertions(+), 85 deletions(-) create mode 100755 transport/lwm2m/src/main/data/credentials/shell/lwM2M_credentials.sh create mode 100644 transport/lwm2m/src/main/data/credentials/shell/lwM2M_keygen.properties diff --git a/common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh b/common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh index 767e79016b..6a1ad298ac 100755 --- a/common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh +++ b/common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # # Copyright © 2016-2020 The Thingsboard Authors # @@ -15,12 +15,147 @@ # limitations under the License. # -# source the properties: +#p) CLIENT_CN=LwX50900000000 +#s) client_start=0 +#f) client_finish=1 +#a) CLIENT_ALIAS=client_alias_00000000 +#b) BOOTSTRAP_ALIAS=bootstrap +#d) SERVER_ALIAS=server +#j) SERVER_STORE=serverKeyStore.jks +#k) CLIENT_STORE=clientKeyStore.jks +#c) CLIENT_STORE_PWD=client_ks_password +#w) SERVER_STORE_PWD=server_ks_password + +#while test $# -gt 0; do +# case "$1" in +# -h|--help) +# echo "$package - attempt to capture frames" +# echo " " +# echo "$package [options] application [arguments]" +# echo " " +# echo "options:" +# echo "-h, --help show brief help" +# echo "-a, --action=ACTION specify an action to use" +# echo "-o, --output-dir=DIR specify a directory to store output in" +# exit 0 +# ;; +# -a) +# shift +# if test $# -gt 0; then +# export PROCESS=$1 +# else +# echo "no process specified" +# exit 1 +# fi +# shift +# ;; +# --action*) +# export PROCESS=`echo $1 | sed -e 's/^[^=]*=//g'` +# shift +# ;; +# -o) +# shift +# if test $# -gt 0; then +# export OUTPUT=$1 +# else +# echo "no output dir specified" +# exit 1 +# fi +# shift +# ;; +# --output-dir*) +# export OUTPUT=`echo $1 | sed -e 's/^[^=]*=//g'` +# shift +# ;; +# *) +# break +# ;; +# esac +#done + + +while getopts p:s:f:a:b:d:j:k:c:w: flag; do + case "${flag}" in + p) client_prefix=${OPTARG} ;; + s) client_start=${OPTARG} ;; + f) client_finish=${OPTARG} ;; + a) client_alias=${OPTARG} ;; + b) bootstrap_alias=${OPTARG} ;; + d) server_alias=${OPTARG} ;; + j) key_store_server_file=${OPTARG} ;; + k) key_store_client_file=${OPTARG} ;; + c) client_key_store_pwd=${OPTARG} ;; + w) server_key_store_pwd=${OPTARG} ;; + esac +done + +# cd to dir of script script_dir=$(dirname $0) echo "script_dir: $script_dir" cd $script_dir +# source the properties: . ./lwM2M_keygen.properties + +if [ -n "$client_prefix" ]; then + CLIENT_PREFIX=$client_prefix +fi + +if [ -z "$client_start" ]; then + client_start=0 +fi + +if [ -z "$client_finish" ]; then + client_finish=1 +fi + +if [ -n "$client_alias" ]; then + CLIENT_ALIAS=$client_alias +fi + +if [ -n "$bootstrap_alias" ]; then + BOOTSTRAP_ALIAS=$bootstrap_alias +fi + +if [ -n "$server_alias" ]; then + SERVER_ALIAS=$server_alias +fi + +if [ -n "$key_store_server_file" ]; then + SERVER_STORE=$key_store_server_file +fi + +if [ -n "$key_store_client_file" ]; then + CLIENT_STORE=$key_store_client_file +fi + +if [ -n "$client_key_store_pwd" ]; then + CLIENT_STORE_PWD=$client_key_store_pwd +fi + +if [ -n "$server_key_store_pwd" ]; then + SERVER_STORE_PWD=$server_key_store_pwd +fi + +echo "==Start==" +echo "CLIENT_PREFIX: $CLIENT_PREFIX" +echo "client_start: $client_start" +echo "client_finish: $client_finish" +echo "CLIENT_ALIAS: $CLIENT_ALIAS" +echo "BOOTSTRAP_ALIAS: $BOOTSTRAP_ALIAS" +echo "SERVER_ALIAS: $SERVER_ALIAS" +echo "SERVER_STORE: $SERVER_STORE" +echo "CLIENT_STORE: $CLIENT_STORE" +echo "CLIENT_STORE_PWD: $CLIENT_STORE_PWD" +echo "SERVER_STORE_PWD: $SERVER_STORE_PWD" + +end_point() { + echo "$CLIENT_PREFIX$(printf "%08d" $CLIENT_NUMBER)" +} +client_alias_point() { + echo "$CLIENT_ALIAS$(printf "%08d" $CLIENT_NUMBER)" +} + # Generation of the keystore. echo "${H0}====START========${RESET}" echo "${H1}Server Keystore : ${RESET}" @@ -55,7 +190,7 @@ keytool \ -exportcert \ -alias $SERVER_ALIAS \ -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD | \ + -storepass $SERVER_STORE_PWD | keytool \ -importcert \ -alias $SERVER_SELF_ALIAS \ @@ -70,22 +205,22 @@ keytool \ -alias $SERVER_ALIAS \ -dname "CN=$SERVER_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD | \ + -storepass $SERVER_STORE_PWD | keytool \ -gencert \ -alias $ROOT_KEY_ALIAS \ -keystore $SERVER_STORE \ -storepass $SERVER_STORE_PWD \ -storetype $STORETYPE \ - -validity $VALIDITY | \ - keytool \ - -importcert \ - -alias $SERVER_ALIAS \ - -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD + -validity $VALIDITY | + keytool \ + -importcert \ + -alias $SERVER_ALIAS \ + -keystore $SERVER_STORE \ + -storepass $SERVER_STORE_PWD echo -echo "${H2}Creating server key and self-signed certificate ...${RESET}" +echo "${H2}Creating bootstrap key and self-signed certificate ...${RESET}" keytool \ -genkeypair \ -alias $BOOTSTRAP_ALIAS \ @@ -100,7 +235,7 @@ keytool \ -exportcert \ -alias $BOOTSTRAP_ALIAS \ -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD | \ + -storepass $SERVER_STORE_PWD | keytool \ -importcert \ -alias $BOOTSTRAP_SELF_ALIAS \ @@ -115,54 +250,53 @@ keytool \ -alias $BOOTSTRAP_ALIAS \ -dname "CN=$BOOTSTRAP_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD | \ + -storepass $SERVER_STORE_PWD | keytool \ -gencert \ -alias $ROOT_KEY_ALIAS \ -keystore $SERVER_STORE \ -storepass $SERVER_STORE_PWD \ -storetype $STORETYPE \ - -validity $VALIDITY | \ - keytool \ - -importcert \ - -alias $BOOTSTRAP_ALIAS \ - -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD - + -validity $VALIDITY | + keytool \ + -importcert \ + -alias $BOOTSTRAP_ALIAS \ + -keystore $SERVER_STORE \ + -storepass $SERVER_STORE_PWD echo echo "${H1}Client Keystore : ${RESET}" echo "${H1}==================${RESET}" -echo "${H2}Creating client key and self-signed certificate with expected CN...${RESET}" -keytool \ - -genkeypair \ - -alias $CLIENT_ALIAS \ - -keyalg EC \ - -dname "CN=$CLIENT_SELF_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ - -validity $VALIDITY \ - -storetype $STORETYPE \ - -keypass $CLIENT_STORE_PWD \ - -keystore $CLIENT_STORE \ - -storepass $CLIENT_STORE_PWD -keytool \ - -exportcert \ - -alias $CLIENT_ALIAS \ - -keystore $CLIENT_STORE \ - -storepass $CLIENT_STORE_PWD | \ - keytool \ - -importcert \ - -alias $CLIENT_SELF_ALIAS \ - -keystore $CLIENT_STORE \ - -storepass $CLIENT_STORE_PWD \ - -noprompt +#echo "${H2}Creating client key and self-signed certificate with expected CN...${RESET}" +#keytool \ +# -genkeypair \ +# -alias $CLIENT_ALIAS \ +# -keyalg EC \ +# -dname "CN=$CLIENT_SELF_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ +# -validity $VALIDITY \ +# -storetype $STORETYPE \ +# -keypass $CLIENT_STORE_PWD \ +# -keystore $CLIENT_STORE \ +# -storepass $CLIENT_STORE_PWD +#keytool \ +# -exportcert \ +# -alias $CLIENT_ALIAS \ +# -keystore $CLIENT_STORE \ +# -storepass $CLIENT_STORE_PWD | \ +# keytool \ +# -importcert \ +# -alias $CLIENT_SELF_ALIAS \ +# -keystore $CLIENT_STORE \ +# -storepass $CLIENT_STORE_PWD \ +# -noprompt echo -echo "${H2}Import root certificate just to be able to import ned by root CA with expected CN...${RESET}" +echo "${H2}Import root certificate just to be able to import need by root CA with expected CN...${RESET}" keytool \ -exportcert \ -alias $ROOT_KEY_ALIAS \ -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD | \ + -storepass $SERVER_STORE_PWD | keytool \ -importcert \ -alias $ROOT_KEY_ALIAS \ @@ -170,27 +304,85 @@ keytool \ -storepass $CLIENT_STORE_PWD \ -noprompt -echo -echo "${H2}Creating client certificate signed by root CA with expected CN...${RESET}" -keytool \ - -certreq \ - -alias $CLIENT_ALIAS \ - -dname "CN=$CLIENT_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ - -keystore $CLIENT_STORE \ - -storepass $CLIENT_STORE_PWD | \ +#echo +#echo "${H2}Creating client certificate signed by root CA with expected CN...${RESET}" +#keytool \ +# -certreq \ +# -alias $CLIENT_ALIAS \ +# -dname "CN=$CLIENT_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ +# -keystore $CLIENT_STORE \ +# -storepass $CLIENT_STORE_PWD | \ +# keytool \ +# -gencert \ +# -alias $ROOT_KEY_ALIAS \ +# -keystore $SERVER_STORE \ +# -storepass $SERVER_STORE_PWD \ +# -storetype $STORETYPE \ +# -validity $VALIDITY | \ +# keytool \ +# -importcert \ +# -alias $CLIENT_ALIAS \ +# -keystore $CLIENT_STORE \ +# -storepass $CLIENT_STORE_PWD \ +# -noprompt + +cert_end_point() { + echo "${H2}Creating client key and self-signed certificate with expected CN $CLIENT_SELF_CN ${RESET}" keytool \ - -gencert \ - -alias $ROOT_KEY_ALIAS \ - -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD \ + -genkeypair \ + -alias $CLIENT_CN_ALIAS \ + -keyalg EC \ + -dname "CN=$CLIENT_SELF_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ + -validity $VALIDITY \ -storetype $STORETYPE \ - -validity $VALIDITY | \ + -keypass $CLIENT_STORE_PWD \ + -keystore $CLIENT_STORE \ + -storepass $CLIENT_STORE_PWD + keytool \ + -exportcert \ + -alias $CLIENT_CN_ALIAS \ + -keystore $CLIENT_STORE \ + -storepass $CLIENT_STORE_PWD | + keytool \ + -importcert \ + -alias $CLIENT_SELF_ALIAS \ + -keystore $CLIENT_STORE \ + -storepass $CLIENT_STORE_PWD \ + -noprompt + + echo + echo "${H2}Creating client certificate signed by root CA with expected $CLIENT_CN_NAME ${RESET}" + keytool \ + -certreq \ + -alias $CLIENT_CN_ALIAS \ + -dname "CN=$CLIENT_CN_NAME, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ + -keystore $CLIENT_STORE \ + -storepass $CLIENT_STORE_PWD | + keytool \ + -gencert \ + -alias $ROOT_KEY_ALIAS \ + -keystore $SERVER_STORE \ + -storepass $SERVER_STORE_PWD \ + -storetype $STORETYPE \ + -validity $VALIDITY | keytool \ -importcert \ - -alias $CLIENT_ALIAS \ + -alias $CLIENT_CN_ALIAS \ -keystore $CLIENT_STORE \ -storepass $CLIENT_STORE_PWD \ -noprompt +} + +while [ "$CLIENT_NUMBER" != "$client_finish" ]; do + CLIENT_CN_NAME=$(end_point) + CLIENT_CN_ALIAS=$(client_alias_point) + echo "$CLIENT_CN_NAME" + echo "$CLIENT_CN_ALIAS" + cert_end_point + CLIENT_NUMBER=$(($CLIENT_NUMBER + 1)) + echo "number $CLIENT_NUMBER" + echo "finish $client_finish" +done echo echo "${H0}!!! Warning ${H2}Migrate ${H1}${SERVER_STORE} ${H2}to ${H1}PKCS12 ${H2}which is an industry standard format..${RESET}" diff --git a/common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_keygen.properties b/common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_keygen.properties index 27e5fa57c7..18f851e4dd 100644 --- a/common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_keygen.properties +++ b/common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_keygen.properties @@ -17,7 +17,7 @@ # Keystore common parameters ROOT_KEY_ALIAS=rootCA DOMAIN_SUFFIX="$(hostname)" -ROOT_CN="$DOMAIN_SUFFIX rootCA" +ROOT_CN="$DOMAIN_SUFFIX $ROOT_KEY_ALIAS" ORGANIZATIONAL_UNIT=Thingsboard ORGANIZATION=Thingsboard CITY=SF @@ -27,23 +27,22 @@ VALIDITY=36500 #days STORETYPE="JKS" #Server -SERVER_STORE=serverKeyStore.jks -SERVER_STORE_PWD=server_ks_password -SERVER_ALIAS=server +SERVER_STORE=serverKeyStore1.jks +SERVER_STORE_PWD=server_ks_password1 +SERVER_ALIAS=server1 SERVER_CN="$DOMAIN_SUFFIX server LwM2M signed by root CA" SERVER_SELF_ALIAS=server_self_signed SERVER_SELF_CN="$DOMAIN_SUFFIX server LwM2M self-signed" -BOOTSTRAP_ALIAS=bootstrap +BOOTSTRAP_ALIAS=bootstrap1 BOOTSTRAP_CN="$DOMAIN_SUFFIX bootstrap server LwM2M signed by root CA" BOOTSTRAP_SELF_ALIAS=bootstrap_self_signed BOOTSTRAP_SELF_CN="$DOMAIN_SUFFIX bootstrap server LwM2M self-signed" # Client -CLIENT_STORE=clientKeyStore.jks -CLIENT_STORE_PWD=client_ks_password -CLIENT_ALIAS=client -#CLIENT_CN=client_lwm2m_x509 -CLIENT_CN=LwX50900000000 +CLIENT_STORE=clientKeyStore1.jks +CLIENT_STORE_PWD=client_ks_password1 +CLIENT_ALIAS=client_alias_1 +CLIENT_PREFIX=LwX509_ CLIENT_SELF_ALIAS=client_self_signed CLIENT_SELF_CN="$DOMAIN_SUFFIX client LwM2M self-signed" diff --git a/transport/lwm2m/src/main/data/credentials/shell/lwM2M_credentials.sh b/transport/lwm2m/src/main/data/credentials/shell/lwM2M_credentials.sh new file mode 100755 index 0000000000..6a1ad298ac --- /dev/null +++ b/transport/lwm2m/src/main/data/credentials/shell/lwM2M_credentials.sh @@ -0,0 +1,403 @@ +#!/bin/bash +# +# Copyright © 2016-2020 The Thingsboard Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +#p) CLIENT_CN=LwX50900000000 +#s) client_start=0 +#f) client_finish=1 +#a) CLIENT_ALIAS=client_alias_00000000 +#b) BOOTSTRAP_ALIAS=bootstrap +#d) SERVER_ALIAS=server +#j) SERVER_STORE=serverKeyStore.jks +#k) CLIENT_STORE=clientKeyStore.jks +#c) CLIENT_STORE_PWD=client_ks_password +#w) SERVER_STORE_PWD=server_ks_password + +#while test $# -gt 0; do +# case "$1" in +# -h|--help) +# echo "$package - attempt to capture frames" +# echo " " +# echo "$package [options] application [arguments]" +# echo " " +# echo "options:" +# echo "-h, --help show brief help" +# echo "-a, --action=ACTION specify an action to use" +# echo "-o, --output-dir=DIR specify a directory to store output in" +# exit 0 +# ;; +# -a) +# shift +# if test $# -gt 0; then +# export PROCESS=$1 +# else +# echo "no process specified" +# exit 1 +# fi +# shift +# ;; +# --action*) +# export PROCESS=`echo $1 | sed -e 's/^[^=]*=//g'` +# shift +# ;; +# -o) +# shift +# if test $# -gt 0; then +# export OUTPUT=$1 +# else +# echo "no output dir specified" +# exit 1 +# fi +# shift +# ;; +# --output-dir*) +# export OUTPUT=`echo $1 | sed -e 's/^[^=]*=//g'` +# shift +# ;; +# *) +# break +# ;; +# esac +#done + + +while getopts p:s:f:a:b:d:j:k:c:w: flag; do + case "${flag}" in + p) client_prefix=${OPTARG} ;; + s) client_start=${OPTARG} ;; + f) client_finish=${OPTARG} ;; + a) client_alias=${OPTARG} ;; + b) bootstrap_alias=${OPTARG} ;; + d) server_alias=${OPTARG} ;; + j) key_store_server_file=${OPTARG} ;; + k) key_store_client_file=${OPTARG} ;; + c) client_key_store_pwd=${OPTARG} ;; + w) server_key_store_pwd=${OPTARG} ;; + esac +done + +# cd to dir of script +script_dir=$(dirname $0) +echo "script_dir: $script_dir" +cd $script_dir +# source the properties: +. ./lwM2M_keygen.properties + + +if [ -n "$client_prefix" ]; then + CLIENT_PREFIX=$client_prefix +fi + +if [ -z "$client_start" ]; then + client_start=0 +fi + +if [ -z "$client_finish" ]; then + client_finish=1 +fi + +if [ -n "$client_alias" ]; then + CLIENT_ALIAS=$client_alias +fi + +if [ -n "$bootstrap_alias" ]; then + BOOTSTRAP_ALIAS=$bootstrap_alias +fi + +if [ -n "$server_alias" ]; then + SERVER_ALIAS=$server_alias +fi + +if [ -n "$key_store_server_file" ]; then + SERVER_STORE=$key_store_server_file +fi + +if [ -n "$key_store_client_file" ]; then + CLIENT_STORE=$key_store_client_file +fi + +if [ -n "$client_key_store_pwd" ]; then + CLIENT_STORE_PWD=$client_key_store_pwd +fi + +if [ -n "$server_key_store_pwd" ]; then + SERVER_STORE_PWD=$server_key_store_pwd +fi + +echo "==Start==" +echo "CLIENT_PREFIX: $CLIENT_PREFIX" +echo "client_start: $client_start" +echo "client_finish: $client_finish" +echo "CLIENT_ALIAS: $CLIENT_ALIAS" +echo "BOOTSTRAP_ALIAS: $BOOTSTRAP_ALIAS" +echo "SERVER_ALIAS: $SERVER_ALIAS" +echo "SERVER_STORE: $SERVER_STORE" +echo "CLIENT_STORE: $CLIENT_STORE" +echo "CLIENT_STORE_PWD: $CLIENT_STORE_PWD" +echo "SERVER_STORE_PWD: $SERVER_STORE_PWD" + +end_point() { + echo "$CLIENT_PREFIX$(printf "%08d" $CLIENT_NUMBER)" +} +client_alias_point() { + echo "$CLIENT_ALIAS$(printf "%08d" $CLIENT_NUMBER)" +} + +# Generation of the keystore. +echo "${H0}====START========${RESET}" +echo "${H1}Server Keystore : ${RESET}" +echo "${H1}==================${RESET}" +echo "${H2}Creating the trusted root CA key and certificate...${RESET}" +# -keysize +# 1024 (when using -genkeypair) +keytool \ + -genkeypair \ + -alias $ROOT_KEY_ALIAS \ + -keyalg EC \ + -dname "CN=$ROOT_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ + -validity $VALIDITY \ + -storetype $STORETYPE \ + -keypass $SERVER_STORE_PWD \ + -keystore $SERVER_STORE \ + -storepass $SERVER_STORE_PWD + +echo +echo "${H2}Creating server key and self-signed certificate ...${RESET}" +keytool \ + -genkeypair \ + -alias $SERVER_ALIAS \ + -keyalg EC \ + -dname "CN=$SERVER_SELF_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ + -validity $VALIDITY \ + -storetype $STORETYPE \ + -keypass $SERVER_STORE_PWD \ + -keystore $SERVER_STORE \ + -storepass $SERVER_STORE_PWD +keytool \ + -exportcert \ + -alias $SERVER_ALIAS \ + -keystore $SERVER_STORE \ + -storepass $SERVER_STORE_PWD | + keytool \ + -importcert \ + -alias $SERVER_SELF_ALIAS \ + -keystore $SERVER_STORE \ + -storepass $SERVER_STORE_PWD \ + -noprompt + +echo +echo "${H2}Creating server certificate signed by root CA...${RESET}" +keytool \ + -certreq \ + -alias $SERVER_ALIAS \ + -dname "CN=$SERVER_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ + -keystore $SERVER_STORE \ + -storepass $SERVER_STORE_PWD | + keytool \ + -gencert \ + -alias $ROOT_KEY_ALIAS \ + -keystore $SERVER_STORE \ + -storepass $SERVER_STORE_PWD \ + -storetype $STORETYPE \ + -validity $VALIDITY | + keytool \ + -importcert \ + -alias $SERVER_ALIAS \ + -keystore $SERVER_STORE \ + -storepass $SERVER_STORE_PWD + +echo +echo "${H2}Creating bootstrap key and self-signed certificate ...${RESET}" +keytool \ + -genkeypair \ + -alias $BOOTSTRAP_ALIAS \ + -keyalg EC \ + -dname "CN=$BOOTSTRAP_SELF_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ + -validity $VALIDITY \ + -storetype $STORETYPE \ + -keypass $SERVER_STORE_PWD \ + -keystore $SERVER_STORE \ + -storepass $SERVER_STORE_PWD +keytool \ + -exportcert \ + -alias $BOOTSTRAP_ALIAS \ + -keystore $SERVER_STORE \ + -storepass $SERVER_STORE_PWD | + keytool \ + -importcert \ + -alias $BOOTSTRAP_SELF_ALIAS \ + -keystore $SERVER_STORE \ + -storepass $SERVER_STORE_PWD \ + -noprompt + +echo +echo "${H2}Creating bootstrap certificate signed by root CA...${RESET}" +keytool \ + -certreq \ + -alias $BOOTSTRAP_ALIAS \ + -dname "CN=$BOOTSTRAP_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ + -keystore $SERVER_STORE \ + -storepass $SERVER_STORE_PWD | + keytool \ + -gencert \ + -alias $ROOT_KEY_ALIAS \ + -keystore $SERVER_STORE \ + -storepass $SERVER_STORE_PWD \ + -storetype $STORETYPE \ + -validity $VALIDITY | + keytool \ + -importcert \ + -alias $BOOTSTRAP_ALIAS \ + -keystore $SERVER_STORE \ + -storepass $SERVER_STORE_PWD + +echo +echo "${H1}Client Keystore : ${RESET}" +echo "${H1}==================${RESET}" +#echo "${H2}Creating client key and self-signed certificate with expected CN...${RESET}" +#keytool \ +# -genkeypair \ +# -alias $CLIENT_ALIAS \ +# -keyalg EC \ +# -dname "CN=$CLIENT_SELF_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ +# -validity $VALIDITY \ +# -storetype $STORETYPE \ +# -keypass $CLIENT_STORE_PWD \ +# -keystore $CLIENT_STORE \ +# -storepass $CLIENT_STORE_PWD +#keytool \ +# -exportcert \ +# -alias $CLIENT_ALIAS \ +# -keystore $CLIENT_STORE \ +# -storepass $CLIENT_STORE_PWD | \ +# keytool \ +# -importcert \ +# -alias $CLIENT_SELF_ALIAS \ +# -keystore $CLIENT_STORE \ +# -storepass $CLIENT_STORE_PWD \ +# -noprompt + +echo +echo "${H2}Import root certificate just to be able to import need by root CA with expected CN...${RESET}" +keytool \ + -exportcert \ + -alias $ROOT_KEY_ALIAS \ + -keystore $SERVER_STORE \ + -storepass $SERVER_STORE_PWD | + keytool \ + -importcert \ + -alias $ROOT_KEY_ALIAS \ + -keystore $CLIENT_STORE \ + -storepass $CLIENT_STORE_PWD \ + -noprompt + +#echo +#echo "${H2}Creating client certificate signed by root CA with expected CN...${RESET}" +#keytool \ +# -certreq \ +# -alias $CLIENT_ALIAS \ +# -dname "CN=$CLIENT_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ +# -keystore $CLIENT_STORE \ +# -storepass $CLIENT_STORE_PWD | \ +# keytool \ +# -gencert \ +# -alias $ROOT_KEY_ALIAS \ +# -keystore $SERVER_STORE \ +# -storepass $SERVER_STORE_PWD \ +# -storetype $STORETYPE \ +# -validity $VALIDITY | \ +# keytool \ +# -importcert \ +# -alias $CLIENT_ALIAS \ +# -keystore $CLIENT_STORE \ +# -storepass $CLIENT_STORE_PWD \ +# -noprompt + +cert_end_point() { + echo "${H2}Creating client key and self-signed certificate with expected CN $CLIENT_SELF_CN ${RESET}" + keytool \ + -genkeypair \ + -alias $CLIENT_CN_ALIAS \ + -keyalg EC \ + -dname "CN=$CLIENT_SELF_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ + -validity $VALIDITY \ + -storetype $STORETYPE \ + -keypass $CLIENT_STORE_PWD \ + -keystore $CLIENT_STORE \ + -storepass $CLIENT_STORE_PWD + keytool \ + -exportcert \ + -alias $CLIENT_CN_ALIAS \ + -keystore $CLIENT_STORE \ + -storepass $CLIENT_STORE_PWD | + keytool \ + -importcert \ + -alias $CLIENT_SELF_ALIAS \ + -keystore $CLIENT_STORE \ + -storepass $CLIENT_STORE_PWD \ + -noprompt + + echo + echo "${H2}Creating client certificate signed by root CA with expected $CLIENT_CN_NAME ${RESET}" + keytool \ + -certreq \ + -alias $CLIENT_CN_ALIAS \ + -dname "CN=$CLIENT_CN_NAME, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ + -keystore $CLIENT_STORE \ + -storepass $CLIENT_STORE_PWD | + keytool \ + -gencert \ + -alias $ROOT_KEY_ALIAS \ + -keystore $SERVER_STORE \ + -storepass $SERVER_STORE_PWD \ + -storetype $STORETYPE \ + -validity $VALIDITY | + keytool \ + -importcert \ + -alias $CLIENT_CN_ALIAS \ + -keystore $CLIENT_STORE \ + -storepass $CLIENT_STORE_PWD \ + -noprompt +} + +while [ "$CLIENT_NUMBER" != "$client_finish" ]; do + CLIENT_CN_NAME=$(end_point) + CLIENT_CN_ALIAS=$(client_alias_point) + echo "$CLIENT_CN_NAME" + echo "$CLIENT_CN_ALIAS" + cert_end_point + CLIENT_NUMBER=$(($CLIENT_NUMBER + 1)) + echo "number $CLIENT_NUMBER" + echo "finish $client_finish" +done + +echo +echo "${H0}!!! Warning ${H2}Migrate ${H1}${SERVER_STORE} ${H2}to ${H1}PKCS12 ${H2}which is an industry standard format..${RESET}" +keytool \ + -importkeystore \ + -srckeystore $SERVER_STORE \ + -destkeystore $SERVER_STORE \ + -deststoretype pkcs12 \ + -srcstorepass $SERVER_STORE_PWD + +echo +echo "${H0}!!! Warning ${H2}Migrate ${H1}${CLIENT_STORE} ${H2}to ${H1}PKCS12 ${H2}which is an industry standard format..${RESET}" +keytool \ + -importkeystore \ + -srckeystore $CLIENT_STORE \ + -destkeystore $CLIENT_STORE \ + -deststoretype pkcs12 \ + -srcstorepass $CLIENT_STORE_PWD diff --git a/transport/lwm2m/src/main/data/credentials/shell/lwM2M_keygen.properties b/transport/lwm2m/src/main/data/credentials/shell/lwM2M_keygen.properties new file mode 100644 index 0000000000..18f851e4dd --- /dev/null +++ b/transport/lwm2m/src/main/data/credentials/shell/lwM2M_keygen.properties @@ -0,0 +1,57 @@ +# +# Copyright © 2016-2017 The Thingsboard Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Keystore common parameters +ROOT_KEY_ALIAS=rootCA +DOMAIN_SUFFIX="$(hostname)" +ROOT_CN="$DOMAIN_SUFFIX $ROOT_KEY_ALIAS" +ORGANIZATIONAL_UNIT=Thingsboard +ORGANIZATION=Thingsboard +CITY=SF +STATE_OR_PROVINCE=CA +TWO_LETTER_COUNTRY_CODE=US +VALIDITY=36500 #days +STORETYPE="JKS" + +#Server +SERVER_STORE=serverKeyStore1.jks +SERVER_STORE_PWD=server_ks_password1 +SERVER_ALIAS=server1 +SERVER_CN="$DOMAIN_SUFFIX server LwM2M signed by root CA" +SERVER_SELF_ALIAS=server_self_signed +SERVER_SELF_CN="$DOMAIN_SUFFIX server LwM2M self-signed" +BOOTSTRAP_ALIAS=bootstrap1 +BOOTSTRAP_CN="$DOMAIN_SUFFIX bootstrap server LwM2M signed by root CA" +BOOTSTRAP_SELF_ALIAS=bootstrap_self_signed +BOOTSTRAP_SELF_CN="$DOMAIN_SUFFIX bootstrap server LwM2M self-signed" + +# Client +CLIENT_STORE=clientKeyStore1.jks +CLIENT_STORE_PWD=client_ks_password1 +CLIENT_ALIAS=client_alias_1 +CLIENT_PREFIX=LwX509_ +CLIENT_SELF_ALIAS=client_self_signed +CLIENT_SELF_CN="$DOMAIN_SUFFIX client LwM2M self-signed" + +# Color output stuff +red=`tput setaf 1` +green=`tput setaf 2` +blue=`tput setaf 4` +bold=`tput bold` +H0=${red}${bold} +H1=${green}${bold} +H2=${blue} +RESET=`tput sgr0` diff --git a/transport/lwm2m/src/main/data/models/LwM2M_BinaryAppDataContainer-v1_0_1.xml b/transport/lwm2m/src/main/data/models/LwM2M_BinaryAppDataContainer-v1_0_1.xml index 374dac72bc..b111d3b321 100644 --- a/transport/lwm2m/src/main/data/models/LwM2M_BinaryAppDataContainer-v1_0_1.xml +++ b/transport/lwm2m/src/main/data/models/LwM2M_BinaryAppDataContainer-v1_0_1.xml @@ -1,20 +1,3 @@ -  --> From 9cdd916276757ed2ca5e41c502af7c46e8e457be Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Fri, 15 Jan 2021 10:45:18 +0200 Subject: [PATCH 031/249] Lwm2m: back: for test2 --- .../src/main/data/models/LwM2M_BinaryAppDataContainer-v1_0_1.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/transport/lwm2m/src/main/data/models/LwM2M_BinaryAppDataContainer-v1_0_1.xml b/transport/lwm2m/src/main/data/models/LwM2M_BinaryAppDataContainer-v1_0_1.xml index 6381ec2245..cd6182596c 100644 --- a/transport/lwm2m/src/main/data/models/LwM2M_BinaryAppDataContainer-v1_0_1.xml +++ b/transport/lwm2m/src/main/data/models/LwM2M_BinaryAppDataContainer-v1_0_1.xml @@ -59,7 +59,6 @@ The above license is used as a license under copyright only. Please reference the OMA IPR Policy for patent licensing terms: https://www.omaspecworks.org/about/intellectual-property-rights/ ---> --> From cd6a76de862efc81fc4c9f6138d76244b896d994 Mon Sep 17 00:00:00 2001 From: Vladyslav Date: Fri, 15 Jan 2021 13:06:39 +0200 Subject: [PATCH 032/249] Improvement/lwm2m/refactoring 1 (#3956) UI: Refactoring lwm2m --- .../app/core/http/device-profile.service.ts | 21 +- .../device/device-credentials.component.html | 3 +- .../device/device-credentials.component.ts | 37 +-- .../home/components/home-components.module.ts | 2 +- .../lwm2m-device-config-server.component.html | 57 ++-- .../lwm2m-device-config-server.component.ts | 45 ++- ...ile-transport-configuration.component.html | 9 +- ...ofile-transport-configuration.component.ts | 269 +++++++++--------- .../device/lwm2m/security-config.models.ts | 1 - 9 files changed, 228 insertions(+), 216 deletions(-) diff --git a/ui-ngx/src/app/core/http/device-profile.service.ts b/ui-ngx/src/app/core/http/device-profile.service.ts index 16f6edb512..22ff52e99b 100644 --- a/ui-ngx/src/app/core/http/device-profile.service.ts +++ b/ui-ngx/src/app/core/http/device-profile.service.ts @@ -22,9 +22,7 @@ import { Observable } from 'rxjs'; import { PageData } from '@shared/models/page/page-data'; import { DeviceProfile, DeviceProfileInfo, DeviceTransportType } from '@shared/models/device.models'; import { isDefinedAndNotNull } from '@core/utils'; -import { - ObjectLwM2M, ServerSecurityConfig -} from "../../modules/home/components/profile/device/lwm2m/profile-config.models"; +import { ObjectLwM2M, ServerSecurityConfig } from '@home/components/profile/device/lwm2m/profile-config.models'; @Injectable({ providedIn: 'root' @@ -43,16 +41,23 @@ export class DeviceProfileService { return this.http.get(`/api/deviceProfile/${deviceProfileId}`, defaultHttpOptionsFromConfig(config)); } - public getLwm2mObjects(objectIds: number [], config?: RequestConfig): Observable { - return this.http.get(`/api/lwm2m/deviceProfile/${objectIds}`, defaultHttpOptionsFromConfig(config)); + public getLwm2mObjects(objectIds: number[], config?: RequestConfig): Observable> { + return this.http.get>(`/api/lwm2m/deviceProfile/${objectIds}`, defaultHttpOptionsFromConfig(config)); } - public getLwm2mBootstrapSecurityInfo(securityMode: string, bootstrapServerIs: boolean, config?: RequestConfig): Observable { - return this.http.get(`/api/lwm2m/deviceProfile/bootstrap/${securityMode}/${bootstrapServerIs}`, defaultHttpOptionsFromConfig(config)); + public getLwm2mBootstrapSecurityInfo(securityMode: string, bootstrapServerIs: boolean, + config?: RequestConfig): Observable { + return this.http.get( + `/api/lwm2m/deviceProfile/bootstrap/${securityMode}/${bootstrapServerIs}`, + defaultHttpOptionsFromConfig(config) + ); } public getLwm2mObjectsPage(pageLink: PageLink, config?: RequestConfig): Observable> { - return this.http.get>(`/api/lwm2m/deviceProfile/objects${pageLink.toQuery()}`, defaultHttpOptionsFromConfig(config)); + return this.http.get>( + `/api/lwm2m/deviceProfile/objects${pageLink.toQuery()}`, + defaultHttpOptionsFromConfig(config) + ); } public saveDeviceProfile(deviceProfile: DeviceProfile, config?: RequestConfig): Observable { diff --git a/ui-ngx/src/app/modules/home/components/device/device-credentials.component.html b/ui-ngx/src/app/modules/home/components/device/device-credentials.component.html index 44337d30a5..9243feb18a 100644 --- a/ui-ngx/src/app/modules/home/components/device/device-credentials.component.html +++ b/ui-ngx/src/app/modules/home/components/device/device-credentials.component.html @@ -90,9 +90,8 @@
diff --git a/ui-ngx/src/app/modules/home/components/device/device-credentials.component.ts b/ui-ngx/src/app/modules/home/components/device/device-credentials.component.ts index 4c622747ef..b6eb364b2f 100644 --- a/ui-ngx/src/app/modules/home/components/device/device-credentials.component.ts +++ b/ui-ngx/src/app/modules/home/components/device/device-credentials.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Inject, Input, OnDestroy, OnInit } from '@angular/core'; +import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core'; import { ControlValueAccessor, FormBuilder, @@ -41,8 +41,7 @@ import { DeviceCredentialsDialogLwm2mData, END_POINT, getDefaultSecurityConfig, - JSON_ALL_CONFIG, - SecurityConfigModels + JSON_ALL_CONFIG } from '@home/pages/device/lwm2m/security-config.models'; import { TranslateService } from '@ngx-translate/core'; import { MatDialog } from '@angular/material/dialog'; @@ -197,6 +196,7 @@ export class DeviceCredentialsComponent implements ControlValueAccessor, OnInit, this.deviceCredentialsFormGroup.get('credentialsBasic').disable({emitEvent: false}); break; case DeviceCredentialsType.X509_CERTIFICATE: + case DeviceCredentialsType.LWM2M_CREDENTIALS: this.deviceCredentialsFormGroup.get('credentialsValue').setValidators([Validators.required]); this.deviceCredentialsFormGroup.get('credentialsValue').updateValueAndValidity({emitEvent: false}); this.deviceCredentialsFormGroup.get('credentialsId').setValidators([]); @@ -211,13 +211,6 @@ export class DeviceCredentialsComponent implements ControlValueAccessor, OnInit, this.deviceCredentialsFormGroup.get('credentialsValue').setValidators([]); this.deviceCredentialsFormGroup.get('credentialsValue').updateValueAndValidity({emitEvent: false}); break; - case DeviceCredentialsType.LWM2M_CREDENTIALS: - this.deviceCredentialsFormGroup.get('credentialsValue').setValidators([Validators.required]); - this.deviceCredentialsFormGroup.get('credentialsValue').updateValueAndValidity({emitEvent: false}); - this.deviceCredentialsFormGroup.get('credentialsId').setValidators([]); - this.deviceCredentialsFormGroup.get('credentialsId').updateValueAndValidity({emitEvent: false}); - this.deviceCredentialsFormGroup.get('credentialsBasic').disable({emitEvent: false}); - break; } } @@ -245,27 +238,39 @@ export class DeviceCredentialsComponent implements ControlValueAccessor, OnInit, }); } - openSecurityInfoLwM2mDialog($event: Event, value: string, id: string): void { + openSecurityInfoLwM2mDialog($event: Event): void { if ($event) { $event.stopPropagation(); $event.preventDefault(); } + let credentialsValue = this.deviceCredentialsFormGroup.get('credentialsValue').value; + if (credentialsValue === null || credentialsValue.length === 0) { + credentialsValue = getDefaultSecurityConfig(); + } else { + credentialsValue = JSON.parse(credentialsValue); + } + const credentialsId = this.deviceCredentialsFormGroup.get('credentialsId').value || DEFAULT_END_POINT; this.dialog.open(SecurityConfigComponent, { disableClose: true, panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], data: { - jsonAllConfig: (value === null || value.length === 0) ? getDefaultSecurityConfig() as SecurityConfigModels : JSON.parse(value) as SecurityConfigModels, - endPoint: (id === null) ? DEFAULT_END_POINT : id, - isNew: (id === null || value === null || value.length === 0) + jsonAllConfig: credentialsValue, + endPoint: credentialsId } }).afterClosed().subscribe( (res) => { if (res) { - this.deviceCredentialsFormGroup.get('credentialsValue').patchValue((Object.keys(res[JSON_ALL_CONFIG]).length === 0 || JSON.stringify(res[JSON_ALL_CONFIG]) === "[{}]") ? null : JSON.stringify(res[JSON_ALL_CONFIG])); - this.deviceCredentialsFormGroup.get('credentialsId').patchValue((Object.keys(res[END_POINT]).length === 0 || JSON.stringify(res[END_POINT]) === "[{}]") ? null : JSON.stringify(res[END_POINT]).split('\"').join('')); + this.deviceCredentialsFormGroup.patchValue({ + credentialsValue: this.isDefautLw2mResponse(res[JSON_ALL_CONFIG]) ? null : JSON.stringify(res[JSON_ALL_CONFIG]), + credentialsId: this.isDefautLw2mResponse(res[END_POINT]) ? null : JSON.stringify(res[END_POINT]).split('\"').join('') + }); this.deviceCredentialsFormGroup.get('credentialsValue').markAsDirty(); } } ); } + + private isDefautLw2mResponse(response: object): boolean { + return Object.keys(response).length === 0 || JSON.stringify(response) === '[{}]'; + } } diff --git a/ui-ngx/src/app/modules/home/components/home-components.module.ts b/ui-ngx/src/app/modules/home/components/home-components.module.ts index 67f86cb812..03124d7a65 100644 --- a/ui-ngx/src/app/modules/home/components/home-components.module.ts +++ b/ui-ngx/src/app/modules/home/components/home-components.module.ts @@ -307,7 +307,7 @@ import { Lwm2mProfileComponentsModule } from '@home/components/profile/device/lw EditAlarmDetailsDialogComponent, DeviceProfileProvisionConfigurationComponent, AlarmScheduleComponent, - Lwm2mProfileComponentsModule, + // Lwm2mProfileComponentsModule, SmsProviderConfigurationComponent, AwsSnsProviderConfigurationComponent, TwilioSmsProviderConfigurationComponent diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html index 0e10a8e843..5f8c1080bc 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html @@ -21,10 +21,9 @@
{{ 'device-profile.lwm2m.mode' | translate }} - + + [value]="securityMode"> {{ credentialTypeLwM2MNamesMap.get(securityConfigLwM2MType[securityMode]) }} @@ -87,33 +86,31 @@ {{ 'device-profile.lwm2m.bootstrap-server' | translate }}
-
-
- - {{ 'device-profile.lwm2m.server-public-key' | translate }} - - {{serverPublicKey.value?.length || 0}}/{{lenMaxServerPublicKey}} - - {{ 'device-profile.lwm2m.server-public-key' | translate }} - {{ 'device-profile.lwm2m.required' | translate }} - - - {{ 'device-profile.lwm2m.client-key' | translate }} - {{ 'device-profile.lwm2m.pattern_hex_dec_182' | translate }} - - - {{ 'device-profile.lwm2m.client-key' | translate }} - {{ 'device-profile.lwm2m.pattern_hex_dec' | translate }} - - -
+
+ + {{ 'device-profile.lwm2m.server-public-key' | translate }} + + {{serverPublicKey.value?.length || 0}}/{{lenMaxServerPublicKey}} + + {{ 'device-profile.lwm2m.server-public-key' | translate }} + {{ 'device-profile.lwm2m.required' | translate }} + + + {{ 'device-profile.lwm2m.client-key' | translate }} + {{ 'device-profile.lwm2m.pattern_hex_dec_182' | translate }} + + + {{ 'device-profile.lwm2m.client-key' | translate }} + {{ 'device-profile.lwm2m.pattern_hex_dec' | translate }} + +
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts index c5d56aa85a..01352af36e 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts @@ -43,7 +43,6 @@ import { DeviceProfileService } from '@core/http/device-profile.service'; @Component({ selector: 'tb-profile-lwm2m-device-config-server', templateUrl: './lwm2m-device-config-server.component.html', - styleUrls: [], providers: [ { provide: NG_VALUE_ACCESSOR, @@ -55,8 +54,8 @@ import { DeviceProfileService } from '@core/http/device-profile.service'; export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAccessor, Validators { - valuePrev = null as any; private requiredValue: boolean; + valuePrev = null; serverFormGroup: FormGroup; securityConfigLwM2MType = SECURITY_CONFIG_MODE; securityConfigLwM2MTypes = Object.keys(SECURITY_CONFIG_MODE); @@ -69,7 +68,7 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc disabled: boolean; @Input() - bootstrapServerIs: boolean + bootstrapServerIs: boolean; get required(): boolean { return this.requiredValue; @@ -107,7 +106,7 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc } updateValueFields(serverData: ServerSecurityConfig): void { - serverData['bootstrapServerIs'] = this.bootstrapServerIs; + serverData.bootstrapServerIs = this.bootstrapServerIs; this.serverFormGroup.patchValue(serverData, {emitEvent: false}); this.serverFormGroup.get('bootstrapServerIs').disable(); const securityMode = this.serverFormGroup.get('securityMode').value as SECURITY_CONFIG_MODE; @@ -132,21 +131,22 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc this.serverFormGroup.get('serverPublicKey').setValidators([Validators.required, Validators.pattern(KEY_PUBLIC_REGEXP_X509)]); break; } - this.checkValueWithNewValidate(); + this.serverFormGroup.updateValueAndValidity(); + // this.checkValueWithNewValidate(); } - checkValueWithNewValidate(): void { - this.serverFormGroup.patchValue({ - host: this.serverFormGroup.get('host').value, - port: this.serverFormGroup.get('port').value, - bootstrapServerIs: this.serverFormGroup.get('bootstrapServerIs').value, - serverPublicKey: this.serverFormGroup.get('serverPublicKey').value, - clientHoldOffTime: this.serverFormGroup.get('clientHoldOffTime').value, - serverId: this.serverFormGroup.get('serverId').value, - bootstrapServerAccountTimeout: this.serverFormGroup.get('bootstrapServerAccountTimeout').value, - }, - {emitEvent: true}); - } + // checkValueWithNewValidate(): void { + // this.serverFormGroup.patchValue({ + // host: this.serverFormGroup.get('host').value, + // port: this.serverFormGroup.get('port').value, + // bootstrapServerIs: this.serverFormGroup.get('bootstrapServerIs').value, + // serverPublicKey: this.serverFormGroup.get('serverPublicKey').value, + // clientHoldOffTime: this.serverFormGroup.get('clientHoldOffTime').value, + // serverId: this.serverFormGroup.get('serverId').value, + // bootstrapServerAccountTimeout: this.serverFormGroup.get('bootstrapServerAccountTimeout').value, + // }, + // {emitEvent: true}); + // } writeValue(value: any): void { if (value) { @@ -154,8 +154,7 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc } } - private propagateChange = (v: any) => { - }; + private propagateChange = (v: any) => {}; registerOnChange(fn: any): void { this.propagateChange = fn; @@ -164,8 +163,8 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc private propagateChangeState(value: any): void { if (value !== undefined) { if (this.valuePrev === null) { - this.valuePrev = "init"; - } else if (this.valuePrev === "init") { + this.valuePrev = 'init'; + } else if (this.valuePrev === 'init') { this.valuePrev = value; } else if (JSON.stringify(value) !== JSON.stringify(this.valuePrev)) { this.valuePrev = value; @@ -192,7 +191,7 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc } getServerGroup(): FormGroup { - const port = (this.bootstrapServerIs) ? DEFAULT_PORT_BOOTSTRAP_NO_SEC : DEFAULT_PORT_SERVER_NO_SEC; + const port = this.bootstrapServerIs ? DEFAULT_PORT_BOOTSTRAP_NO_SEC : DEFAULT_PORT_SERVER_NO_SEC; return this.fb.group({ host: [this.window.location.hostname, this.required ? [Validators.required] : []], port: [port, this.required ? [Validators.required] : []], @@ -202,7 +201,7 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc clientHoldOffTime: [DEFAULT_CLIENT_HOLD_OFF_TIME, this.required ? [Validators.required] : []], serverId: [DEFAULT_ID_SERVER, this.required ? [Validators.required] : []], bootstrapServerAccountTimeout: ['', this.required ? [Validators.required] : []], - }) + }); } getLwm2mBootstrapSecurityInfo(mode: string) { diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html index 846f991e3e..5e9c5d27f4 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html @@ -40,8 +40,7 @@ -
{{ 'device-profile.lwm2m.servers' | translate | uppercase }}
+
{{ 'device-profile.lwm2m.servers' | translate | uppercase }}
@@ -93,8 +92,7 @@ -
{{ 'device-profile.lwm2m.bootstrap-server' | translate | uppercase }}
+
{{ 'device-profile.lwm2m.bootstrap-server' | translate | uppercase }}
@@ -110,8 +108,7 @@ -
{{ 'device-profile.lwm2m.lwm2m-server' | translate | uppercase }}
+
{{ 'device-profile.lwm2m.lwm2m-server' | translate | uppercase }}
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts index 2cc6fe819e..9071fc4a2b 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts @@ -33,7 +33,7 @@ import { OBSERVE, OBSERVE_ATTR, TELEMETRY, - ObjectLwM2M, getDefaultProfileConfig, KEY_NAME, Instance + ObjectLwM2M, getDefaultProfileConfig, KEY_NAME, Instance, ProfileConfigModels, ResourceLwM2M } from "./profile-config.models"; import { DeviceProfileService } from "@core/http/device-profile.service"; import { deepClone, isUndefined } from "@core/utils"; @@ -44,7 +44,6 @@ import { isNotNullOrUndefined } from 'codelyzer/util/isNotNullOrUndefined'; @Component({ selector: 'tb-profile-lwm2m-device-transport-configuration', templateUrl: './lwm2m-device-profile-transport-configuration.component.html', - styleUrls: [], providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => Lwm2mDeviceProfileTransportConfigurationComponent), @@ -53,6 +52,10 @@ import { isNotNullOrUndefined } from 'codelyzer/util/isNotNullOrUndefined'; }) export class Lwm2mDeviceProfileTransportConfigurationComponent implements ControlValueAccessor, OnInit, Validators { + private configurationValue: ProfileConfigModels; + private requiredValue: boolean; + private disabled = false; + lwm2mDeviceProfileTransportConfFormGroup: FormGroup; observeAttr = OBSERVE_ATTR as string; observe = OBSERVE as string; @@ -62,9 +65,6 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro bootstrapServers: string; bootstrapServer: string; lwm2mServer: string; - private configurationValue: {}; - private requiredValue: boolean; - private disabled = false as boolean; sortFunction = this.sortObjectKeyPathJson; get required(): boolean { @@ -76,8 +76,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro this.requiredValue = coerceBooleanProperty(value); } - private propagateChange = (v: any) => { - }; + private propagateChange = (v: any) => { }; constructor(private store: Store, private fb: FormBuilder, @@ -85,17 +84,17 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro @Inject(WINDOW) private window: Window) { this.lwm2mDeviceProfileTransportConfFormGroup = this.fb.group({ objectIds: [{}, Validators.required], - observeAttrTelemetry: [{'clientLwM2M': [] as ObjectLwM2M []}, Validators.required], + observeAttrTelemetry: [{clientLwM2M: [] as ObjectLwM2M[]}, Validators.required], shortId: [null, Validators.required], lifetime: [null, Validators.required], defaultMinPeriod: [null, Validators.required], notifIfDisabled: [true, []], - binding: ["U", Validators.required], + binding: ['U', Validators.required], bootstrapServer: [null, Validators.required], lwm2mServer: [null, Validators.required], configurationJson: [null, Validators.required], }); - this.lwm2mDeviceProfileTransportConfFormGroup.valueChanges.subscribe(value => { + this.lwm2mDeviceProfileTransportConfFormGroup.valueChanges.subscribe(() => { if (!this.disabled) { this.updateModel(); } @@ -122,7 +121,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } writeValue(value: any | null): void { - value = (Object.keys(value).length == 0) ? getDefaultProfileConfig() : value; + value = (Object.keys(value).length === 0) ? getDefaultProfileConfig() : value; this.lwm2mDeviceProfileTransportConfFormGroup.patchValue({ configurationJson: value }, @@ -132,14 +131,14 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } private initWriteValue(): void { - let modelValue = {"objectIds": null, "objectsList": []}; + const modelValue = {objectIds: null, objectsList: []}; modelValue.objectIds = this.getObjectsFromJsonAllConfig(); if (modelValue.objectIds !== null) { this.deviceProfileService.getLwm2mObjects(modelValue.objectIds).subscribe( - (objectsList) => { - modelValue.objectsList = objectsList; - this.updateWriteValue(modelValue); - } + (objectsList) => { + modelValue.objectsList = objectsList; + this.updateWriteValue(modelValue); + } ); } else { this.updateWriteValue(modelValue); @@ -147,17 +146,17 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } private updateWriteValue(value: any): void { - let objectsList = deepClone(value.objectsList); + const objectsList = deepClone(value.objectsList); this.lwm2mDeviceProfileTransportConfFormGroup.patchValue({ objectIds: value, observeAttrTelemetry: {clientLwM2M: this.getObserveAttrTelemetryObjects(objectsList)}, - shortId: this.configurationValue['bootstrap'].servers.shortId, - lifetime: this.configurationValue['bootstrap'].servers.lifetime, - defaultMinPeriod: this.configurationValue['bootstrap'].servers.defaultMinPeriod, - notifIfDisabled: this.configurationValue['bootstrap'].servers.notifIfDisabled, - binding: this.configurationValue['bootstrap'].servers.binding, - bootstrapServer: this.configurationValue['bootstrap'].bootstrapServer, - lwm2mServer: this.configurationValue['bootstrap'].lwm2mServer + shortId: this.configurationValue.bootstrap.servers.shortId, + lifetime: this.configurationValue.bootstrap.servers.lifetime, + defaultMinPeriod: this.configurationValue.bootstrap.servers.defaultMinPeriod, + notifIfDisabled: this.configurationValue.bootstrap.servers.notifIfDisabled, + binding: this.configurationValue.bootstrap.servers.binding, + bootstrapServer: this.configurationValue.bootstrap.bootstrapServer, + lwm2mServer: this.configurationValue.bootstrap.lwm2mServer }, {emitEvent: false}); } @@ -174,10 +173,10 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro private updateObserveAttrTelemetryObjectFormGroup(objectsList: ObjectLwM2M[]) { this.lwm2mDeviceProfileTransportConfFormGroup.patchValue({ - observeAttrTelemetry: {clientLwM2M: this.getObserveAttrTelemetryObjects(objectsList)} - }, - {emitEvent: false}); - this.lwm2mDeviceProfileTransportConfFormGroup.get("observeAttrTelemetry").markAsPristine({ + observeAttrTelemetry: {clientLwM2M: this.getObserveAttrTelemetryObjects(objectsList)} + }, + {emitEvent: false}); + this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').markAsPristine({ onlySelf: true }); } @@ -188,9 +187,11 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } upDateValueToJsonTab_0(): void { - if (!this.lwm2mDeviceProfileTransportConfFormGroup.get("observeAttrTelemetry").pristine) { - this.upDateObserveAttrTelemetryFromGroupToJson(this.lwm2mDeviceProfileTransportConfFormGroup.get("observeAttrTelemetry").value['clientLwM2M']); - this.lwm2mDeviceProfileTransportConfFormGroup.get("observeAttrTelemetry").markAsPristine({ + if (!this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').pristine) { + this.upDateObserveAttrTelemetryFromGroupToJson( + this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').value.clientLwM2M + ); + this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').markAsPristine({ onlySelf: true }); this.upDateJsonAllConfig(); @@ -200,14 +201,14 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro upDateValueToJsonTab_1(): void { this.upDateValueServersToJson(); if (!this.lwm2mDeviceProfileTransportConfFormGroup.get('bootstrapServer').pristine) { - this.configurationValue['bootstrap'].bootstrapServer = this.lwm2mDeviceProfileTransportConfFormGroup.get('bootstrapServer').value; + this.configurationValue.bootstrap.bootstrapServer = this.lwm2mDeviceProfileTransportConfFormGroup.get('bootstrapServer').value; this.lwm2mDeviceProfileTransportConfFormGroup.get('bootstrapServer').markAsPristine({ onlySelf: true }); this.upDateJsonAllConfig(); } if (!this.lwm2mDeviceProfileTransportConfFormGroup.get('lwm2mServer').pristine) { - this.configurationValue['bootstrap'].lwm2mServer = this.lwm2mDeviceProfileTransportConfFormGroup.get('lwm2mServer').value; + this.configurationValue.bootstrap.lwm2mServer = this.lwm2mDeviceProfileTransportConfFormGroup.get('lwm2mServer').value; this.lwm2mDeviceProfileTransportConfFormGroup.get('lwm2mServer').markAsPristine({ onlySelf: true }); @@ -216,36 +217,37 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } upDateValueServersToJson(): void { + const bootstrapServers = this.configurationValue.bootstrap.servers; if (!this.lwm2mDeviceProfileTransportConfFormGroup.get('shortId').pristine) { - this.configurationValue['bootstrap'].servers.shortId = this.lwm2mDeviceProfileTransportConfFormGroup.get('shortId').value; + bootstrapServers.shortId = this.lwm2mDeviceProfileTransportConfFormGroup.get('shortId').value; this.lwm2mDeviceProfileTransportConfFormGroup.get('shortId').markAsPristine({ onlySelf: true }); this.upDateJsonAllConfig(); } if (!this.lwm2mDeviceProfileTransportConfFormGroup.get('lifetime').pristine) { - this.configurationValue['bootstrap'].servers.lifetime = this.lwm2mDeviceProfileTransportConfFormGroup.get('lifetime').value; + bootstrapServers.lifetime = this.lwm2mDeviceProfileTransportConfFormGroup.get('lifetime').value; this.lwm2mDeviceProfileTransportConfFormGroup.get('lifetime').markAsPristine({ onlySelf: true }); this.upDateJsonAllConfig(); } if (!this.lwm2mDeviceProfileTransportConfFormGroup.get('defaultMinPeriod').pristine) { - this.configurationValue['bootstrap'].servers.defaultMinPeriod = this.lwm2mDeviceProfileTransportConfFormGroup.get('defaultMinPeriod').value; + bootstrapServers.defaultMinPeriod = this.lwm2mDeviceProfileTransportConfFormGroup.get('defaultMinPeriod').value; this.lwm2mDeviceProfileTransportConfFormGroup.get('defaultMinPeriod').markAsPristine({ onlySelf: true }); this.upDateJsonAllConfig(); } if (!this.lwm2mDeviceProfileTransportConfFormGroup.get('notifIfDisabled').pristine) { - this.configurationValue['bootstrap'].servers.notifIfDisabled = this.lwm2mDeviceProfileTransportConfFormGroup.get('notifIfDisabled').value; + bootstrapServers.notifIfDisabled = this.lwm2mDeviceProfileTransportConfFormGroup.get('notifIfDisabled').value; this.lwm2mDeviceProfileTransportConfFormGroup.get('notifIfDisabled').markAsPristine({ onlySelf: true }); this.upDateJsonAllConfig(); } if (!this.lwm2mDeviceProfileTransportConfFormGroup.get('binding').pristine) { - this.configurationValue['bootstrap'].servers.binding = this.lwm2mDeviceProfileTransportConfFormGroup.get('binding').value; + bootstrapServers.binding = this.lwm2mDeviceProfileTransportConfFormGroup.get('binding').value; this.lwm2mDeviceProfileTransportConfFormGroup.get('binding').markAsPristine({ onlySelf: true }); @@ -254,122 +256,130 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } getObserveAttrTelemetryObjects(listObject: ObjectLwM2M[]): ObjectLwM2M [] { - let clientObserveAttr = deepClone(listObject) as ObjectLwM2M[]; + const clientObserveAttr = deepClone(listObject); if (this.configurationValue[this.observeAttr]) { - let observeArray = this.configurationValue[this.observeAttr][this.observe] as Array; - let attributeArray = this.configurationValue[this.observeAttr][this.attribute] as Array; - let telemetryArray = this.configurationValue[this.observeAttr][this.telemetry] as Array; - let keyNameJson = this.configurationValue[this.observeAttr][this.keyName] as JsonObject; - if (this.includesInstancesNo(attributeArray, telemetryArray, clientObserveAttr)) { + const observeArray = this.configurationValue[this.observeAttr][this.observe] as Array; + const attributeArray = this.configurationValue[this.observeAttr][this.attribute] as Array; + const telemetryArray = this.configurationValue[this.observeAttr][this.telemetry] as Array; + const keyNameJson = this.configurationValue[this.observeAttr][this.keyName] as JsonObject; + if (this.includesInstancesNo(attributeArray, telemetryArray)) { this.addInstances(attributeArray, telemetryArray, clientObserveAttr); } - if (observeArray) this.updateObserveAttrTelemetryObjects(observeArray, clientObserveAttr, "observe"); - if (attributeArray) this.updateObserveAttrTelemetryObjects(attributeArray, clientObserveAttr, "attribute"); - if (telemetryArray) this.updateObserveAttrTelemetryObjects(telemetryArray, clientObserveAttr, "telemetry"); - if (keyNameJson) this.updateKeyNameObjects(deepClone(keyNameJson), clientObserveAttr); + if (observeArray) { + this.updateObserveAttrTelemetryObjects(observeArray, clientObserveAttr, 'observe'); + } + if (attributeArray) { + this.updateObserveAttrTelemetryObjects(attributeArray, clientObserveAttr, 'attribute'); + } + if (telemetryArray) { + this.updateObserveAttrTelemetryObjects(telemetryArray, clientObserveAttr, 'telemetry'); + } + if (keyNameJson) { + this.updateKeyNameObjects(deepClone(keyNameJson), clientObserveAttr); + } } clientObserveAttr.forEach(obj => { - obj.instances.sort((a,b) => a.id - b.id);; - }) + obj.instances.sort((a, b) => a.id - b.id); + }); return clientObserveAttr; } - includesInstancesNo(attributeArray: Array, telemetryArray: Array, clientObserveAttr: ObjectLwM2M[]): boolean { - let isIdIndex = (element) => !element.includes("/0/"); - return attributeArray.findIndex(isIdIndex) >= 0 || telemetryArray.findIndex(isIdIndex) >= 0 - + includesInstancesNo(attributeArray: Array, telemetryArray: Array): boolean { + const isIdIndex = (element) => !element.includes('/0/'); + return attributeArray.findIndex(isIdIndex) >= 0 || telemetryArray.findIndex(isIdIndex) >= 0; } addInstances(attributeArray: Array, telemetryArray: Array, clientObserveAttr: ObjectLwM2M[]): void { - let attr = [] as Array; - [...attributeArray].filter(x => (!x.includes("/0/"))).forEach(x => { + const attr = [] as Array; + [...attributeArray].filter(x => (!x.includes('/0/'))).forEach(x => { attr.push(this.convertPathToInstance(x)); }); - let telemetry = [] as Array; - [...telemetryArray].filter(x => (!x.includes("/0/"))).forEach(x => { + const telemetry = [] as Array; + [...telemetryArray].filter(x => (!x.includes('/0/'))).forEach(x => { telemetry.push(this.convertPathToInstance(x)); }); - let instancesNoZero = new Set(attr.concat(telemetry).sort()); + const instancesNoZero = new Set(attr.concat(telemetry).sort()); instancesNoZero.forEach(path => { - let pathParameter = Array.from(path.split('/'), Number); - let objectLwM2M = clientObserveAttr.find(x => (x.id === pathParameter[0])); + const pathParameter = Array.from(path.split('/'), Number); + const objectLwM2M = clientObserveAttr.find(x => (x.id === pathParameter[0])); if (objectLwM2M) { - let instance = deepClone(objectLwM2M.instances[0]) as Instance; + const instance = deepClone(objectLwM2M.instances[0]) as Instance; instance.id = pathParameter[1]; objectLwM2M.instances.push(instance); } - }) + }); } convertPathToInstance(path: string): string { - let newX = Array.from(path.substring(1).split('/'), Number); - return [newX[0], newX[1]].join("/"); + const newX = Array.from(path.substring(1).split('/'), Number); + return [newX[0], newX[1]].join('/'); } updateObserveAttrTelemetryObjects(isParameter: Array, clientObserveAttr: ObjectLwM2M[], nameParameter: string): void { isParameter.forEach(attr => { - let idKeys = Array.from(attr.substring(1).split('/'), Number); + const idKeys = Array.from(attr.substring(1).split('/'), Number); clientObserveAttr - .forEach(e => { - if (e.id == idKeys[0]) { - let instance = e.instances.find(e => e.id == idKeys[1]); - if (isNotNullOrUndefined(instance)) { - instance.resources.find(e => e.id == idKeys[2])[nameParameter] = true; + .forEach(e => { + if (e.id === idKeys[0]) { + const instance = e.instances.find(itrInstance => itrInstance.id === idKeys[1]); + if (isNotNullOrUndefined(instance)) { + instance.resources.find(resource => resource.id === idKeys[2])[nameParameter] = true; + } } - } - }); + }); }); } updateKeyNameObjects(nameJson: JsonObject, clientObserveAttr: ObjectLwM2M[]): void { - let keyName = JSON.parse(JSON.stringify(nameJson)); - Object.keys(keyName).forEach(function (key) { - let idKeys = Array.from(key.substring(1).split('/'), Number); + const keyName = JSON.parse(JSON.stringify(nameJson)); + Object.keys(keyName).forEach(key => { + const idKeys = Array.from(key.substring(1).split('/'), Number); clientObserveAttr - .forEach(e => { - if (e.id == idKeys[0]) { - e.instances.find(e => e.id == idKeys[1]).resources - .find(e => e.id == idKeys[2]).keyName = keyName[key]; - } - }); + .forEach(e => { + if (e.id === idKeys[0]) { + e.instances + .find(instance => instance.id === idKeys[1]).resources + .find(resource => resource.id === idKeys[2]).keyName = keyName[key]; + } + }); }); } - upDateObserveAttrTelemetryFromGroupToJson(val: ObjectLwM2M []): void { - let observeArray = [] as Array; - let attributeArray = [] as Array; - let telemetryArray = [] as Array; - let observeJson = JSON.parse(JSON.stringify(val)); + upDateObserveAttrTelemetryFromGroupToJson(val: ObjectLwM2M[]): void { + const observeArray: Array = []; + const attributeArray: Array = []; + const telemetryArray: Array = []; + const observeJson: ObjectLwM2M[] = JSON.parse(JSON.stringify(val)); let pathObj; let pathInst; - let pathRes + let pathRes; observeJson.forEach(obj => { Object.entries(obj).forEach(([key, value]) => { if (key === 'id') { pathObj = value; } if (key === 'instances') { - let instancesJson = JSON.parse(JSON.stringify(value)) as []; + const instancesJson = JSON.parse(JSON.stringify(value)) as Instance[]; if (instancesJson.length > 0) { instancesJson.forEach(instance => { - Object.entries(instance).forEach(([key, value]) => { - if (key === 'id') { - pathInst = value; + Object.entries(instance).forEach(([instanceKey, instanceValue]) => { + if (instanceKey === 'id') { + pathInst = instanceValue; } - if (key === 'resources') { - let resourcesJson = JSON.parse(JSON.stringify(value)) as []; + if (instanceKey === 'resources') { + const resourcesJson = JSON.parse(JSON.stringify(instanceValue)) as ResourceLwM2M[]; if (resourcesJson.length > 0) { resourcesJson.forEach(res => { - Object.entries(res).forEach(([key, value]) => { - if (key === 'id') { - // pathRes = value - pathRes = '/' + pathObj + '/' + pathInst + '/' + value; - } else if (key === 'observe' && value) { - observeArray.push(pathRes) - } else if (key === 'attribute' && value) { - attributeArray.push(pathRes) - } else if (key === 'telemetry' && value) { - telemetryArray.push(pathRes) + Object.entries(res).forEach(([resourceKey, resourceValue]) => { + if (resourceKey === 'id') { + // pathRes = resourceValue + pathRes = '/' + pathObj + '/' + pathInst + '/' + resourceValue; + } else if (resourceKey === 'observe' && resourceValue) { + observeArray.push(pathRes); + } else if (resourceKey === 'attribute' && resourceValue) { + attributeArray.push(pathRes); + } else if (resourceKey === 'telemetry' && resourceValue) { + telemetryArray.push(pathRes); } }); }); @@ -396,19 +406,19 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } sortObjectKeyPathJson(key, value) { - if (key == "keyName") { + if (key === 'keyName') { return Object.keys(value).sort((a, b) => { - let aLC = Array.from(a.substring(1).split('/'), Number); - let bLC = Array.from(b.substring(1).split('/'), Number); - return aLC[0] == bLC[0] ? aLC[1] - bLC[1] : aLC[0] - bLC[0]; - }).reduce((r, k) => (r[k] = value[k], r), {}); + const aLC = Array.from(a.substring(1).split('/'), Number); + const bLC = Array.from(b.substring(1).split('/'), Number); + return aLC[0] === bLC[0] ? aLC[1] - bLC[1] : aLC[0] - bLC[0]; + }).reduce((r, k) => r[k] = value[k], {}); } else { - return value + return value; } } updateKeyName(): void { - let paths = new Set(); + const paths = new Set(); if (this.configurationValue[this.observeAttr][this.attribute]) { this.configurationValue[this.observeAttr][this.attribute].forEach(path => { paths.add(path); @@ -419,31 +429,32 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro paths.add(path); }); } - let keyNameNew = {}; + const keyNameNew = {}; paths.forEach(path => { - let pathParameter = this.findIndexsForIds(path); + const pathParameter = this.findIndexsForIds(path); if (pathParameter.length === 3) { - let value = this.lwm2mDeviceProfileTransportConfFormGroup.get("observeAttrTelemetry").value['clientLwM2M'][pathParameter[0]].instances[pathParameter[1]].resources[pathParameter[2]][this.keyName]; - keyNameNew[path] = value; + keyNameNew[path] = this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').value + .clientLwM2M[pathParameter[0]].instances[pathParameter[1]].resources[pathParameter[2]][this.keyName]; } }); - this.configurationValue[this.observeAttr][this.keyName] = this.sortObjectKeyPathJson("keyName", keyNameNew); + this.configurationValue[this.observeAttr][this.keyName] = this.sortObjectKeyPathJson('keyName', keyNameNew); } findIndexsForIds(path: string): number[] { - let pathParameter = Array.from(path.substring(1).split('/'), Number); - let pathParameterIndexes = [] as number[]; - let objectsOld = deepClone(this.lwm2mDeviceProfileTransportConfFormGroup.get("observeAttrTelemetry").value.clientLwM2M) as ObjectLwM2M[]; + const pathParameter = Array.from(path.substring(1).split('/'), Number); + const pathParameterIndexes: number[] = []; + const objectsOld = deepClone( + this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').value.clientLwM2M) as ObjectLwM2M[]; let isIdIndex = (element) => element.id === pathParameter[0]; - let objIndex = objectsOld.findIndex(isIdIndex); + const objIndex = objectsOld.findIndex(isIdIndex); if (objIndex >= 0) { pathParameterIndexes.push(objIndex); isIdIndex = (element) => element.id === pathParameter[1]; - let instIndex = objectsOld[objIndex].instances.findIndex(isIdIndex); + const instIndex = objectsOld[objIndex].instances.findIndex(isIdIndex); if (instIndex >= 0) { pathParameterIndexes.push(instIndex); isIdIndex = (element) => element.id === pathParameter[2]; - let resIndex = objectsOld[objIndex].instances[instIndex].resources.findIndex(isIdIndex); + const resIndex = objectsOld[objIndex].instances[instIndex].resources.findIndex(isIdIndex); if (resIndex >= 0) { pathParameterIndexes.push(resIndex); } @@ -453,7 +464,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } getObjectsFromJsonAllConfig(): number [] { - let objectsIds = new Set(); + const objectsIds = new Set(); if (this.configurationValue[this.observeAttr]) { if (this.configurationValue[this.observeAttr][this.observe]) { this.configurationValue[this.observeAttr][this.observe].forEach(obj => { @@ -488,9 +499,9 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } removeObjectsList(value: ObjectLwM2M): void { - let objectsOld = deepClone(this.lwm2mDeviceProfileTransportConfFormGroup.get("observeAttrTelemetry").value.clientLwM2M); + const objectsOld = deepClone(this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').value.clientLwM2M); const isIdIndex = (element) => element.id === value.id; - let index = objectsOld.findIndex(isIdIndex); + const index = objectsOld.findIndex(isIdIndex); if (index >= 0) { objectsOld.splice(index, 1); } @@ -504,7 +515,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } removeObserveAttrTelemetryFromJson(observeAttrTel: string, id: number): void { - let isIdIndex = (element) => Array.from(element.substring(1).split('/'), Number)[0] === id; + const isIdIndex = (element) => Array.from(element.substring(1).split('/'), Number)[0] === id; let index = this.configurationValue[this.observeAttr][observeAttrTel].findIndex(isIdIndex); while (index >= 0) { this.configurationValue[this.observeAttr][observeAttrTel].splice(index, 1); @@ -513,9 +524,9 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } removeKeyNameFromJson(id: number): void { - let keyNmaeJson = this.configurationValue[this.observeAttr][this.keyName]; - Object.keys(keyNmaeJson).forEach(function (key) { - let idKey = Array.from(key.substring(1).split('/'), Number)[0]; + const keyNmaeJson = this.configurationValue[this.observeAttr][this.keyName]; + Object.keys(keyNmaeJson).forEach(key => { + const idKey = Array.from(key.substring(1).split('/'), Number)[0]; if (idKey === id) { delete keyNmaeJson[key]; } diff --git a/ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config.models.ts b/ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config.models.ts index cd323e2f90..220426f357 100644 --- a/ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config.models.ts +++ b/ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config.models.ts @@ -33,7 +33,6 @@ export const KEY_PUBLIC_REGEXP_X509 = /^[0-9a-fA-F]{0,3000}$/; export interface DeviceCredentialsDialogLwm2mData { jsonAllConfig?: SecurityConfigModels; endPoint?: string; - isNew?: boolean; } export enum SECURITY_CONFIG_MODE { From 79f8b87133eebd25212f9647df5204a73a531905 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Fri, 15 Jan 2021 14:51:55 +0200 Subject: [PATCH 033/249] Lwm2m: back: for test3 --- .../LwM2M_BinaryAppDataContainer-v1_0_1.xml | 77 ++++++++---------- .../LwM2M_BinaryAppDataContainer-v1_0_1.xml | 79 +++++++++---------- 2 files changed, 71 insertions(+), 85 deletions(-) diff --git a/common/transport/lwm2m/src/main/resources/models/LwM2M_BinaryAppDataContainer-v1_0_1.xml b/common/transport/lwm2m/src/main/resources/models/LwM2M_BinaryAppDataContainer-v1_0_1.xml index b111d3b321..0508674743 100644 --- a/common/transport/lwm2m/src/main/resources/models/LwM2M_BinaryAppDataContainer-v1_0_1.xml +++ b/common/transport/lwm2m/src/main/resources/models/LwM2M_BinaryAppDataContainer-v1_0_1.xml @@ -3,61 +3,54 @@ FILE INFORMATION OMA Permanent Document - File: OMA-SUP-LwM2M_BinaryAppDataContainer-V1_0_1-20190221-A + File: OMA-SUP-XML_LWM2M_Bearer_Selection-V1_0_1-20190917-A Type: xml Public Reachable Information Path: http://www.openmobilealliance.org/tech/profiles - Name: LwM2M_BinaryAppDataContainer-v1_0_1.xml + Name: LWM2M_Bearer_Selection-v1_0_1.xml NORMATIVE INFORMATION + This file is not part of a Technical Specification document. - Information about this file can be found in the latest revision of - - OMA-TS-LWM2M_BinaryAppDataContainer-V1_0_1 - - This is available at http://www.openmobilealliance.org/ + The file is also available at http://www.openmobilealliance.org/ Send comments to https://github.com/OpenMobileAlliance/OMA_LwM2M_for_Developers/issues -CHANGE HISTORY - -15062018 Status changed to Approved by DM, Doc Ref # OMA-DM&SE-2018-0061-INP_LWM2M_APPDATA_V1_0_ERP_for_final_Approval -21022019 Status changed to Approved by IPSO, Doc Ref # OMA-IPSO-2019-0025-INP_LwM2M_Object_App_Data_Container_1_0_1_for_Final_Approval LEGAL DISCLAIMER -Copyright 2019 Open Mobile Alliance. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -1. Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. -3. Neither the name of the copyright holder nor the names of its -contributors may be used to endorse or promote products derived -from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. - -The above license is used as a license under copyright only. Please -reference the OMA IPR Policy for patent licensing terms: -https://www.omaspecworks.org/about/intellectual-property-rights/ + Copyright 2019 Open Mobile Alliance. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + The above license is used as a license under copyright only. Please + reference the OMA IPR Policy for patent licensing terms: + https://www.omaspecworks.org/about/intellectual-property-rights/ --> diff --git a/transport/lwm2m/src/main/data/models/LwM2M_BinaryAppDataContainer-v1_0_1.xml b/transport/lwm2m/src/main/data/models/LwM2M_BinaryAppDataContainer-v1_0_1.xml index cd6182596c..0508674743 100644 --- a/transport/lwm2m/src/main/data/models/LwM2M_BinaryAppDataContainer-v1_0_1.xml +++ b/transport/lwm2m/src/main/data/models/LwM2M_BinaryAppDataContainer-v1_0_1.xml @@ -1,63 +1,56 @@ - + From efb671f4806c08196a0a7b05dcfe77e0ee400e29 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Fri, 15 Jan 2021 15:08:31 +0200 Subject: [PATCH 034/249] Lwm2m: back: for test4 --- .../LwM2M_BinaryAppDataContainer-v1_0_1.xml | 140 ------------------ .../LwM2M_BinaryAppDataContainer-v1_0_1.xml | 140 ------------------ 2 files changed, 280 deletions(-) delete mode 100644 common/transport/lwm2m/src/main/resources/models/LwM2M_BinaryAppDataContainer-v1_0_1.xml delete mode 100644 transport/lwm2m/src/main/data/models/LwM2M_BinaryAppDataContainer-v1_0_1.xml diff --git a/common/transport/lwm2m/src/main/resources/models/LwM2M_BinaryAppDataContainer-v1_0_1.xml b/common/transport/lwm2m/src/main/resources/models/LwM2M_BinaryAppDataContainer-v1_0_1.xml deleted file mode 100644 index 0508674743..0000000000 --- a/common/transport/lwm2m/src/main/resources/models/LwM2M_BinaryAppDataContainer-v1_0_1.xml +++ /dev/null @@ -1,140 +0,0 @@ - - - - - BinaryAppDataContainer - - 19 - urn:oma:lwm2m:oma:19 - 1.0 - 1.0 - Multiple - Optional - - Data - RW - - - - Multiple - Mandatory - Opaque - - - - - Data Priority - RW - Single - Optional - Integer - 1 bytes - - - - Data Creation Time - RW - Single - Optional - Time - - - - - Data Description - RW - Single - Optional - String - 32 bytes - - - - Data Format - RW - Single - Optional - String - 32 bytes - - - - App ID - RW - Single - Optional - Integer - 2 bytes - - - - - - diff --git a/transport/lwm2m/src/main/data/models/LwM2M_BinaryAppDataContainer-v1_0_1.xml b/transport/lwm2m/src/main/data/models/LwM2M_BinaryAppDataContainer-v1_0_1.xml deleted file mode 100644 index 0508674743..0000000000 --- a/transport/lwm2m/src/main/data/models/LwM2M_BinaryAppDataContainer-v1_0_1.xml +++ /dev/null @@ -1,140 +0,0 @@ - - - - - BinaryAppDataContainer - - 19 - urn:oma:lwm2m:oma:19 - 1.0 - 1.0 - Multiple - Optional - - Data - RW - - - - Multiple - Mandatory - Opaque - - - - - Data Priority - RW - Single - Optional - Integer - 1 bytes - - - - Data Creation Time - RW - Single - Optional - Time - - - - - Data Description - RW - Single - Optional - String - 32 bytes - - - - Data Format - RW - Single - Optional - String - 32 bytes - - - - App ID - RW - Single - Optional - Integer - 2 bytes - - - - - - From fb460d7215db9dbd0fb93614dabe2e24c9886137 Mon Sep 17 00:00:00 2001 From: Viacheslav Kukhtyn Date: Fri, 15 Jan 2021 16:34:06 +0200 Subject: [PATCH 035/249] Changes after code review --- .../credentials/CertPemCredentials.java | 5 ++-- .../engine/credentials/CredentialsType.java | 29 +++++++++++++++++++ .../rule/engine/mqtt/TbMqttNode.java | 22 +++++++------- .../mqtt/azure/AzureIotHubSasCredentials.java | 13 ++++++--- .../engine/mqtt/azure/TbAzureIotHubNode.java | 19 +++++++++--- .../credentials/MqttAnonymousCredentials.java | 5 ++++ .../credentials/MqttBasicCredentials.java | 6 ++++ .../credentials/MqttCertPemCredentials.java | 5 ++++ .../credentials/MqttClientCredentials.java | 11 ++++--- .../rule/engine/rest/TbHttpClient.java | 28 ++++++++++++++++-- .../credentials/HttpAnonymousCredentials.java | 5 ++++ .../credentials/HttpBasicCredentials.java | 10 +++++-- .../credentials/HttpCertPemCredentials.java | 5 ++++ .../credentials/HttpClientCredentials.java | 14 +++------ .../credentials/HttpBasicCredentialsTest.java | 4 +-- 15 files changed, 139 insertions(+), 42 deletions(-) create mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CredentialsType.java diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CertPemCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CertPemCredentials.java index 64f08fac36..5aa1ede5e9 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CertPemCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CertPemCredentials.java @@ -49,7 +49,6 @@ import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.security.spec.KeySpec; import java.security.spec.PKCS8EncodedKeySpec; -import java.util.Optional; @Data @Slf4j @@ -62,7 +61,7 @@ public class CertPemCredentials { private String privateKey; private String password; - public Optional initSslContext() { + public SslContext initSslContext() { try { Security.addProvider(new BouncyCastleProvider()); SslContextBuilder builder = SslContextBuilder.forClient(); @@ -72,7 +71,7 @@ public class CertPemCredentials { if (StringUtils.hasLength(cert) && StringUtils.hasLength(privateKey)) { builder.keyManager(createAndInitKeyManagerFactory()); } - return Optional.of(builder.build()); + return builder.build(); } catch (Exception e) { log.error("[{}:{}] Creating TLS factory failed!", caCert, cert, e); throw new RuntimeException("Creating TLS factory failed!", e); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CredentialsType.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CredentialsType.java new file mode 100644 index 0000000000..a0d298a9be --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CredentialsType.java @@ -0,0 +1,29 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.credentials; + +public enum CredentialsType { + ANONYMOUS("anonymous"), + BASIC("basic"), + SAS("sas"), + CERT_PEM("cert.PEM"); + + private final String label; + + CredentialsType(String label) { + this.label = label; + } +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java index 63fbb23fc1..47b950554a 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java @@ -21,19 +21,22 @@ import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContextBuilder; import io.netty.util.concurrent.Future; import lombok.extern.slf4j.Slf4j; +import org.springframework.util.StringUtils; import org.thingsboard.mqtt.MqttClient; import org.thingsboard.mqtt.MqttClientConfig; import org.thingsboard.mqtt.MqttConnectResult; -import org.springframework.util.StringUtils; +import org.thingsboard.rule.engine.api.RuleNode; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNode; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; -import org.thingsboard.rule.engine.api.*; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; import javax.net.ssl.SSLException; import java.nio.charset.Charset; -import java.util.Optional; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -97,8 +100,7 @@ public class TbMqttNode implements TbNode { } protected MqttClient initClient(TbContext ctx) throws Exception { - Optional sslContextOpt = initSslContext(); - MqttClientConfig config = sslContextOpt.isPresent() ? new MqttClientConfig(sslContextOpt.get()) : new MqttClientConfig(); + MqttClientConfig config = new MqttClientConfig(getSslContext()); if (!StringUtils.isEmpty(this.mqttNodeConfiguration.getClientId())) { config.setClientId(this.mqttNodeConfiguration.getClientId()); } @@ -125,12 +127,12 @@ public class TbMqttNode implements TbNode { return client; } - private Optional initSslContext() throws SSLException { - Optional result = this.mqttNodeConfiguration.getCredentials().initSslContext(); - if (this.mqttNodeConfiguration.isSsl() && !result.isPresent()) { - result = Optional.of(SslContextBuilder.forClient().build()); + private SslContext getSslContext() throws SSLException { + SslContext sslContext = this.mqttNodeConfiguration.getCredentials().initSslContext(); + if (this.mqttNodeConfiguration.isSsl() && sslContext == null) { + sslContext = SslContextBuilder.forClient().build(); } - return result; + return sslContext; } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/AzureIotHubSasCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/AzureIotHubSasCredentials.java index 172e675ac8..b946b3f754 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/AzureIotHubSasCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/AzureIotHubSasCredentials.java @@ -24,6 +24,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.binary.Base64; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.thingsboard.common.util.AzureIotHubUtil; +import org.thingsboard.rule.engine.credentials.CredentialsType; import org.thingsboard.rule.engine.mqtt.credentials.MqttClientCredentials; import javax.net.ssl.TrustManagerFactory; @@ -32,7 +33,6 @@ import java.security.KeyStore; import java.security.Security; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; -import java.util.Optional; @Data @Slf4j @@ -42,22 +42,27 @@ public class AzureIotHubSasCredentials implements MqttClientCredentials { private String caCert; @Override - public Optional initSslContext() { + public SslContext initSslContext() { try { Security.addProvider(new BouncyCastleProvider()); if (caCert == null || caCert.isEmpty()) { caCert = AzureIotHubUtil.getDefaultCaCert(); } - return Optional.of(SslContextBuilder.forClient() + return SslContextBuilder.forClient() .trustManager(createAndInitTrustManagerFactory()) .clientAuth(ClientAuth.REQUIRE) - .build()); + .build(); } catch (Exception e) { log.error("[{}] Creating TLS factory failed!", caCert, e); throw new RuntimeException("Creating TLS factory failed!", e); } } + @Override + public CredentialsType getType() { + return CredentialsType.SAS; + } + private TrustManagerFactory createAndInitTrustManagerFactory() throws Exception { X509Certificate caCertHolder; caCertHolder = readCertFile(caCert); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNode.java index 2ad0ce58bb..3e2b555a07 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNode.java @@ -25,14 +25,13 @@ import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.rule.engine.credentials.CredentialsType; import org.thingsboard.rule.engine.mqtt.TbMqttNode; import org.thingsboard.rule.engine.mqtt.TbMqttNodeConfiguration; import org.thingsboard.rule.engine.mqtt.credentials.MqttCertPemCredentials; import org.thingsboard.rule.engine.mqtt.credentials.MqttClientCredentials; import org.thingsboard.server.common.data.plugin.ComponentType; -import java.util.Optional; - @Slf4j @RuleNode( type = ComponentType.EXTERNAL, @@ -53,7 +52,18 @@ public class TbAzureIotHubNode extends TbMqttNode { MqttClientCredentials credentials = mqttNodeConfiguration.getCredentials(); mqttNodeConfiguration.setCredentials(new MqttClientCredentials() { @Override - public Optional initSslContext() { + public CredentialsType getType() { + if (credentials instanceof AzureIotHubSasCredentials) { + return CredentialsType.SAS; + } else if (credentials instanceof MqttCertPemCredentials) { + return CredentialsType.CERT_PEM; + } else { + throw new IllegalArgumentException("[" + credentials.getType() + "] is not supported!"); + } + } + + @Override + public SslContext initSslContext() { if (credentials instanceof AzureIotHubSasCredentials) { AzureIotHubSasCredentials sasCredentials = (AzureIotHubSasCredentials) credentials; if (sasCredentials.getCaCert() == null || sasCredentials.getCaCert().isEmpty()) { @@ -82,5 +92,6 @@ public class TbAzureIotHubNode extends TbMqttNode { this.mqttClient = initClient(ctx); } catch (Exception e) { throw new TbNodeException(e); - } } + } + } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttAnonymousCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttAnonymousCredentials.java index dd827f12ce..1896dc2650 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttAnonymousCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttAnonymousCredentials.java @@ -16,6 +16,11 @@ package org.thingsboard.rule.engine.mqtt.credentials; import org.thingsboard.rule.engine.credentials.AnonymousCredentials; +import org.thingsboard.rule.engine.credentials.CredentialsType; public class MqttAnonymousCredentials extends AnonymousCredentials implements MqttClientCredentials { + @Override + public CredentialsType getType() { + return CredentialsType.ANONYMOUS; + } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttBasicCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttBasicCredentials.java index cb9e50c66b..188d25d4cd 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttBasicCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttBasicCredentials.java @@ -17,8 +17,14 @@ package org.thingsboard.rule.engine.mqtt.credentials; import org.thingsboard.mqtt.MqttClientConfig; import org.thingsboard.rule.engine.credentials.BasicCredentials; +import org.thingsboard.rule.engine.credentials.CredentialsType; public class MqttBasicCredentials extends BasicCredentials implements MqttClientCredentials { + @Override + public CredentialsType getType() { + return CredentialsType.BASIC; + } + @Override public void configure(MqttClientConfig config) { config.setUsername(getUsername()); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttCertPemCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttCertPemCredentials.java index aaf5a1f927..b108d1dc48 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttCertPemCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttCertPemCredentials.java @@ -16,6 +16,11 @@ package org.thingsboard.rule.engine.mqtt.credentials; import org.thingsboard.rule.engine.credentials.CertPemCredentials; +import org.thingsboard.rule.engine.credentials.CredentialsType; public class MqttCertPemCredentials extends CertPemCredentials implements MqttClientCredentials { + @Override + public CredentialsType getType() { + return CredentialsType.CERT_PEM; + } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttClientCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttClientCredentials.java index 6d166eb223..e7c72b2ee7 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttClientCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttClientCredentials.java @@ -15,14 +15,14 @@ */ package org.thingsboard.rule.engine.mqtt.credentials; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; import io.netty.handler.ssl.SslContext; import org.thingsboard.mqtt.MqttClientConfig; +import org.thingsboard.rule.engine.credentials.CredentialsType; import org.thingsboard.rule.engine.mqtt.azure.AzureIotHubSasCredentials; -import java.util.Optional; - @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") @JsonSubTypes({ @JsonSubTypes.Type(value = MqttAnonymousCredentials.class, name = "anonymous"), @@ -30,8 +30,11 @@ import java.util.Optional; @JsonSubTypes.Type(value = AzureIotHubSasCredentials.class, name = "sas"), @JsonSubTypes.Type(value = MqttCertPemCredentials.class, name = "cert.PEM")}) public interface MqttClientCredentials { - default Optional initSslContext() { - return Optional.empty(); + @JsonIgnore + CredentialsType getType(); + + default SslContext initSslContext() { + return null; } default void configure(MqttClientConfig config) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java index 5fd7486a4c..102d772056 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java @@ -17,6 +17,7 @@ package org.thingsboard.rule.engine.rest; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContextBuilder; import lombok.Data; import lombok.extern.slf4j.Slf4j; @@ -44,6 +45,10 @@ import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.TbRelationTypes; import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.rule.engine.credentials.CredentialsType; +import org.thingsboard.rule.engine.rest.credentials.HttpBasicCredentials; +import org.thingsboard.rule.engine.rest.credentials.HttpCertPemCredentials; +import org.thingsboard.rule.engine.rest.credentials.HttpClientCredentials; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -133,7 +138,7 @@ public class TbHttpClient { } else { this.eventLoopGroup = new NioEventLoopGroup(); Netty4ClientHttpRequestFactory nettyFactory = new Netty4ClientHttpRequestFactory(this.eventLoopGroup); - nettyFactory.setSslContext(config.getCredentials().initSslContext().orElse(SslContextBuilder.forClient().build())); + nettyFactory.setSslContext(getSslContext(config.getCredentials())); nettyFactory.setReadTimeout(config.getReadTimeoutMs()); httpClient = new AsyncRestTemplate(nettyFactory); } @@ -142,6 +147,18 @@ public class TbHttpClient { } } + private SslContext getSslContext(HttpClientCredentials credentials) throws SSLException { + switch (credentials.getType()) { + case ANONYMOUS: + case BASIC: + return SslContextBuilder.forClient().build(); + case CERT_PEM: + return ((HttpCertPemCredentials) credentials).initSslContext(); + default: + throw new IllegalArgumentException("[" + credentials.getType() + "] is not supported!"); + } + } + private void checkSystemProxyProperties() throws TbNodeException { boolean useHttpProxy = !StringUtils.isEmpty(System.getProperty("http.proxyHost")) && !StringUtils.isEmpty(System.getProperty("http.proxyPort")); boolean useHttpsProxy = !StringUtils.isEmpty(System.getProperty("https.proxyHost")) && !StringUtils.isEmpty(System.getProperty("https.proxyPort")); @@ -226,7 +243,7 @@ public class TbHttpClient { private HttpHeaders prepareHeaders(TbMsgMetaData metaData) { HttpHeaders headers = new HttpHeaders(); config.getHeaders().forEach((k, v) -> headers.add(TbNodeUtils.processPattern(k, metaData), TbNodeUtils.processPattern(v, metaData))); - config.getCredentials().getBasicAuthHeaderValue().ifPresent(v -> headers.add("Authorization", v)); + addAuthorizationHeader(headers); return headers; } @@ -260,4 +277,11 @@ public class TbHttpClient { throw new TbNodeException("Proxy port out of range:" + proxyPort); } } + + private void addAuthorizationHeader(HttpHeaders headers) { + HttpClientCredentials credentials = config.getCredentials(); + if (CredentialsType.BASIC == credentials.getType()) { + headers.add("Authorization", ((HttpBasicCredentials) credentials).getPassword()); + } + } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpAnonymousCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpAnonymousCredentials.java index 3b7eb0b12b..87a2854e4b 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpAnonymousCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpAnonymousCredentials.java @@ -16,6 +16,11 @@ package org.thingsboard.rule.engine.rest.credentials; import org.thingsboard.rule.engine.credentials.AnonymousCredentials; +import org.thingsboard.rule.engine.credentials.CredentialsType; public class HttpAnonymousCredentials extends AnonymousCredentials implements HttpClientCredentials { + @Override + public CredentialsType getType() { + return CredentialsType.ANONYMOUS; + } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpBasicCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpBasicCredentials.java index cf29cd928a..f36d497c02 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpBasicCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpBasicCredentials.java @@ -17,15 +17,19 @@ package org.thingsboard.rule.engine.rest.credentials; import org.apache.commons.codec.binary.Base64; import org.thingsboard.rule.engine.credentials.BasicCredentials; +import org.thingsboard.rule.engine.credentials.CredentialsType; import java.nio.charset.StandardCharsets; -import java.util.Optional; public class HttpBasicCredentials extends BasicCredentials implements HttpClientCredentials { @Override - public Optional getBasicAuthHeaderValue() { + public CredentialsType getType() { + return CredentialsType.BASIC; + } + + public String getBasicAuthHeaderValue() { String authString = getUsername() + ":" + getPassword(); String encodedAuthString = new String(Base64.encodeBase64(authString.getBytes(StandardCharsets.UTF_8))); - return Optional.of("Basic " + encodedAuthString); + return "Basic " + encodedAuthString; } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpCertPemCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpCertPemCredentials.java index bdc1d3b264..f15d7d946d 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpCertPemCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpCertPemCredentials.java @@ -16,6 +16,11 @@ package org.thingsboard.rule.engine.rest.credentials; import org.thingsboard.rule.engine.credentials.CertPemCredentials; +import org.thingsboard.rule.engine.credentials.CredentialsType; public class HttpCertPemCredentials extends CertPemCredentials implements HttpClientCredentials { + @Override + public CredentialsType getType() { + return CredentialsType.CERT_PEM; + } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpClientCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpClientCredentials.java index 4e581354b1..0cf78e59e1 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpClientCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpClientCredentials.java @@ -15,11 +15,10 @@ */ package org.thingsboard.rule.engine.rest.credentials; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; -import io.netty.handler.ssl.SslContext; - -import java.util.Optional; +import org.thingsboard.rule.engine.credentials.CredentialsType; @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") @JsonSubTypes({ @@ -27,12 +26,7 @@ import java.util.Optional; @JsonSubTypes.Type(value = HttpBasicCredentials.class, name = "basic"), @JsonSubTypes.Type(value = HttpCertPemCredentials.class, name = "cert.PEM")}) public interface HttpClientCredentials { - default Optional initSslContext() { - return Optional.empty(); - } - - default Optional getBasicAuthHeaderValue() { - return Optional.empty(); - } + @JsonIgnore + CredentialsType getType(); } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/credentials/HttpBasicCredentialsTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/credentials/HttpBasicCredentialsTest.java index 755735f1d7..59f0e7a72a 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/credentials/HttpBasicCredentialsTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/credentials/HttpBasicCredentialsTest.java @@ -26,8 +26,8 @@ public class HttpBasicCredentialsTest { HttpBasicCredentials credentials = new HttpBasicCredentials(); credentials.setUsername("testUser"); credentials.setPassword("testPwd"); - Optional actualHeaderValue = credentials.getBasicAuthHeaderValue(); - Optional expectedHeaderValue = Optional.of("Basic dGVzdFVzZXI6dGVzdFB3ZA=="); + String actualHeaderValue = credentials.getBasicAuthHeaderValue(); + String expectedHeaderValue = "Basic dGVzdFVzZXI6dGVzdFB3ZA=="; Assert.assertEquals(expectedHeaderValue, actualHeaderValue); } From 1bdd7d69bfc3d148f275e61f3504c0b79a596157 Mon Sep 17 00:00:00 2001 From: zbeacon Date: Fri, 15 Jan 2021 18:55:35 +0200 Subject: [PATCH 036/249] Fix for lastActivityTime in devices created by gateway --- common/queue/src/main/proto/queue.proto | 1 + .../mqtt/session/GatewayDeviceSessionCtx.java | 11 +++++++++++ .../mqtt/session/GatewaySessionHandler.java | 3 +++ .../transport/service/DefaultTransportService.java | 3 ++- .../modules/home/pages/device/device.component.html | 12 +++++++++--- .../modules/home/pages/device/device.component.ts | 10 ++++++++-- ui-ngx/src/assets/locale/locale.constant-en_US.json | 2 ++ 7 files changed, 36 insertions(+), 6 deletions(-) diff --git a/common/queue/src/main/proto/queue.proto b/common/queue/src/main/proto/queue.proto index 6864259617..1d1846dfeb 100644 --- a/common/queue/src/main/proto/queue.proto +++ b/common/queue/src/main/proto/queue.proto @@ -53,6 +53,7 @@ message SessionInfoProto { int64 gwSessionIdLSB = 11; int64 deviceProfileIdMSB = 12; int64 deviceProfileIdLSB = 13; + bool activityTimeFromGatewayDevice = 14; } enum SessionEvent { diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java index 60a2503225..1983c3f68d 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java @@ -15,6 +15,8 @@ */ package org.thingsboard.server.transport.mqtt.session; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.transport.SessionMsgListener; @@ -37,6 +39,14 @@ public class GatewayDeviceSessionCtx extends MqttDeviceAwareSessionContext imple DeviceProfile deviceProfile, ConcurrentMap mqttQoSMap) { super(UUID.randomUUID(), mqttQoSMap); this.parent = parent; + JsonParser parser = new JsonParser(); + boolean activityTimeFromGatewayDevice = Boolean.FALSE; + if ("null".equals(this.parent.getDeviceInfo().getAdditionalInfo())) { + JsonObject additionalInfo = parser.parse(this.parent.getDeviceInfo().getAdditionalInfo()).getAsJsonObject(); + if (additionalInfo.get("activityTimeFromGatewayDevice") != null) { + activityTimeFromGatewayDevice = additionalInfo.get("activityTimeFromGatewayDevice").getAsBoolean(); + } + } setSessionInfo(SessionInfoProto.newBuilder() .setNodeId(parent.getNodeId()) .setSessionIdMSB(sessionId.getMostSignificantBits()) @@ -51,6 +61,7 @@ public class GatewayDeviceSessionCtx extends MqttDeviceAwareSessionContext imple .setGwSessionIdLSB(parent.getSessionId().getLeastSignificantBits()) .setDeviceProfileIdMSB(deviceInfo.getDeviceProfileId().getId().getMostSignificantBits()) .setDeviceProfileIdLSB(deviceInfo.getDeviceProfileId().getId().getLeastSignificantBits()) + .setActivityTimeFromGatewayDevice(activityTimeFromGatewayDevice) .build()); setDeviceInfo(deviceInfo); setDeviceProfile(deviceProfile); diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewaySessionHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewaySessionHandler.java index 73c7347039..15986b930e 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewaySessionHandler.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewaySessionHandler.java @@ -34,6 +34,7 @@ import io.netty.handler.codec.mqtt.MqttPublishMessage; import lombok.extern.slf4j.Slf4j; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; +import org.thingsboard.server.common.data.DeviceInfo; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.common.transport.TransportServiceCallback; @@ -179,6 +180,8 @@ public class GatewaySessionHandler { return deviceSessionCtx.getPayloadAdaptor(); } + public TransportDeviceInfo getDeviceInfo() { return deviceSessionCtx.getDeviceInfo(); } + void deregisterSession(String deviceName) { GatewayDeviceSessionCtx deviceSessionCtx = devices.remove(deviceName); if (deviceSessionCtx != null) { diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java index 5e46a77fb1..472cffef30 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java @@ -510,7 +510,8 @@ public class DefaultTransportService implements TransportService { long lastActivityTime = sessionMD.getLastActivityTime(); TransportProtos.SessionInfoProto sessionInfo = sessionMD.getSessionInfo(); if (sessionInfo.getGwSessionIdMSB() != 0 && - sessionInfo.getGwSessionIdLSB() != 0) { + sessionInfo.getGwSessionIdLSB() != 0 && + sessionInfo.getActivityTimeFromGatewayDevice()) { SessionMetaData gwMetaData = sessions.get(new UUID(sessionInfo.getGwSessionIdMSB(), sessionInfo.getGwSessionIdLSB())); if (gwMetaData != null) { lastActivityTime = Math.max(gwMetaData.getLastActivityTime(), lastActivityTime); diff --git a/ui-ngx/src/app/modules/home/pages/device/device.component.html b/ui-ngx/src/app/modules/home/pages/device/device.component.html index 7f7465a5e6..1ea3b380b9 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device.component.html +++ b/ui-ngx/src/app/modules/home/pages/device/device.component.html @@ -100,9 +100,15 @@ required>
- - {{ 'device.is-gateway' | translate }} - +
+ + {{ 'device.is-gateway' | translate }} + + + {{ 'device.activity-time-from-gateway-device' | translate }} + +
device.description diff --git a/ui-ngx/src/app/modules/home/pages/device/device.component.ts b/ui-ngx/src/app/modules/home/pages/device/device.component.ts index 782ed9e23a..9d865a09af 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device.component.ts +++ b/ui-ngx/src/app/modules/home/pages/device/device.component.ts @@ -84,6 +84,7 @@ export class DeviceComponent extends EntityComponent { additionalInfo: this.fb.group( { gateway: [entity && entity.additionalInfo ? entity.additionalInfo.gateway : false], + activityTimeFromGatewayDevice: [entity && entity.additionalInfo ? entity.additionalInfo.activityTimeFromGatewayDevice: false], description: [entity && entity.additionalInfo ? entity.additionalInfo.description : ''], } ) @@ -96,8 +97,13 @@ export class DeviceComponent extends EntityComponent { this.entityForm.patchValue({deviceProfileId: entity.deviceProfileId}); this.entityForm.patchValue({label: entity.label}); this.entityForm.patchValue({deviceData: entity.deviceData}); - this.entityForm.patchValue({additionalInfo: - {gateway: entity.additionalInfo ? entity.additionalInfo.gateway : false}}); + this.entityForm.patchValue({ + additionalInfo: + { + gateway: entity.additionalInfo ? entity.additionalInfo.gateway : false, + activityTimeFromGatewayDevice: entity.additionalInfo ? entity.additionalInfo.activityTimeFromGatewayDevice : false + } + }); this.entityForm.patchValue({additionalInfo: {description: entity.additionalInfo ? entity.additionalInfo.description : ''}}); } diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 5ebc491c49..25bf43243d 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -906,6 +906,7 @@ "unable-delete-device-alias-title": "Unable to delete device alias", "unable-delete-device-alias-text": "Device alias '{{deviceAlias}}' can't be deleted as it used by the following widget(s):
{{widgetsList}}", "is-gateway": "Is gateway", + "activity-time-from-gateway-device": "Activity time from gateway device", "public": "Public", "device-public": "Device is public", "select-device": "Select device", @@ -1721,6 +1722,7 @@ "entity-field": "Entity field", "access-token": "Access token", "isgateway": "Is Gateway", + "activity-time-from-gateway-device": "Activity time from gateway device", "description": "Description" }, "stepper-text":{ From 85563d7ae83ec64da52d3d9ef64017cbb33c6350 Mon Sep 17 00:00:00 2001 From: Chantsova Ekaterina Date: Mon, 18 Jan 2021 13:23:36 +0200 Subject: [PATCH 037/249] MQTT, REST API call: make CA cert or client cert-key pair optional --- .../resources/public/static/rulenode/rulenode-core-config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js index 0926cb41cb..6d78132629 100644 --- a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js +++ b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js @@ -12,5 +12,5 @@ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - ***************************************************************************** */var g=function(e,t){return(g=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])})(e,t)};function y(e,t){function r(){this.constructor=e}g(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}function b(e,t,r,n){var a,o=arguments.length,i=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,r,n);else for(var l=e.length-1;l>=0;l--)(a=e[l])&&(i=(o<3?a(i):o>3?a(t,r,i):a(t,r))||i);return o>3&&i&&Object.defineProperty(t,r,i),i}function h(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}Object.create;function C(e){var t="function"==typeof Symbol&&Symbol.iterator,r=t&&e[t],n=0;if(r)return r.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}Object.create;var v,F=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.emptyConfigForm},r.prototype.onConfigurationSet=function(e){this.emptyConfigForm=this.fb.group({})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-node-empty-config",template:"
"}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),x=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return y(r,e),r.prototype.configForm=function(){return this.attributesConfigForm},r.prototype.onConfigurationSet=function(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]],notifyDevice:[!e||e.scope,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-attributes-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),T=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.timeseriesConfigForm},r.prototype.onConfigurationSet=function(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-timeseries-config",template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),q=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.rpcRequestConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rpc-request-config",template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),S=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.logConfigForm},r.prototype.onConfigurationSet=function(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.logConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-log-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),I=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.assignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),k=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.clearAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],alarmType:[e?e.alarmType:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-clear-alarm-config",template:'
\n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),N=function(e){function r(t,r,n,o){var i=e.call(this,t)||this;return i.store=t,i.fb=r,i.nodeScriptTestService=n,i.translate=o,i.alarmSeverities=Object.keys(a.AlarmSeverity),i.alarmSeverityTranslationMap=a.alarmSeverityTranslations,i.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],i}return y(r,e),r.prototype.configForm=function(){return this.createAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]]})},r.prototype.validatorTriggers=function(){return["useMessageAlarmData"]},r.prototype.updateValidators=function(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([i.Validators.required]),this.createAlarmConfigForm.get("severity").setValidators([i.Validators.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})},r.prototype.testScript=function(){var e=this,t=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.removeKey=function(e,t){var r=this.createAlarmConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.createAlarmConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.createAlarmConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.createAlarmConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-create-alarm-config",template:'
\n \n \n \n
\n \n
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n \n \n
\n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),V=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return y(r,e),r.prototype.configForm=function(){return this.createRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[i.Validators.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["entityType"]},r.prototype.updateValidators=function(e){var t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==a.EntityType.DEVICE&&t!==a.EntityType.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([i.Validators.required]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-create-relation-config",template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),E=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.msgDelayConfigForm},r.prototype.onConfigurationSet=function(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(1e5)]]})},r.prototype.validatorTriggers=function(){return["useMetadataPeriodInSecondsPatterns"]},r.prototype.updateValidators=function(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([i.Validators.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([i.Validators.required,i.Validators.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-msg-delay-config",template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),A=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return y(r,e),r.prototype.configForm=function(){return this.deleteRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["deleteForSingleEntity","entityType"]},r.prototype.updateValidators=function(e){var t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,r=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&r?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-delete-relation-config",template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),L=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.generatorConfigForm},r.prototype.onConfigurationSet=function(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[i.Validators.required,i.Validators.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[i.Validators.required,i.Validators.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.prepareInputConfig=function(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e},r.prototype.prepareOutputConfig=function(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e},r.prototype.testScript=function(){var e=this,t=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId).subscribe((function(t){t&&e.generatorConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-generator-config",template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent);!function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(v||(v={}));var M,P=new Map([[v.CUSTOMER,"tb.rulenode.originator-customer"],[v.TENANT,"tb.rulenode.originator-tenant"],[v.RELATED,"tb.rulenode.originator-related"],[v.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(M||(M={}));var R,w=new Map([[M.CIRCLE,"tb.rulenode.perimeter-circle"],[M.POLYGON,"tb.rulenode.perimeter-polygon"]]);!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(R||(R={}));var O,D=new Map([[R.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[R.SECONDS,"tb.rulenode.time-unit-seconds"],[R.MINUTES,"tb.rulenode.time-unit-minutes"],[R.HOURS,"tb.rulenode.time-unit-hours"],[R.DAYS,"tb.rulenode.time-unit-days"]]);!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(O||(O={}));var K,B=new Map([[O.METER,"tb.rulenode.range-unit-meter"],[O.KILOMETER,"tb.rulenode.range-unit-kilometer"],[O.FOOT,"tb.rulenode.range-unit-foot"],[O.MILE,"tb.rulenode.range-unit-mile"],[O.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(K||(K={}));var U,j,H,G=new Map([[K.TITLE,"tb.rulenode.entity-details-title"],[K.COUNTRY,"tb.rulenode.entity-details-country"],[K.STATE,"tb.rulenode.entity-details-state"],[K.ZIP,"tb.rulenode.entity-details-zip"],[K.ADDRESS,"tb.rulenode.entity-details-address"],[K.ADDRESS2,"tb.rulenode.entity-details-address2"],[K.PHONE,"tb.rulenode.entity-details-phone"],[K.EMAIL,"tb.rulenode.entity-details-email"],[K.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(U||(U={})),function(e){e.ASC="ASC",e.DESC="DESC"}(j||(j={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(H||(H={}));var z,$=new Map([[H.STANDARD,"tb.rulenode.sqs-queue-standard"],[H.FIFO,"tb.rulenode.sqs-queue-fifo"]]),Q=["anonymous","basic","cert.PEM"],_=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),W=["sas","cert.PEM"],J=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(z||(z={}));var Y=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],Z=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]),X=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=w,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=B,n.timeUnits=Object.keys(R),n.timeUnitsTranslationMap=D,n}return y(r,e),r.prototype.configForm=function(){return this.geoActionConfigForm},r.prototype.onConfigurationSet=function(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[i.Validators.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterType").setValidators([]):this.geoActionConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoActionConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoActionConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.msgCountConfigForm},r.prototype.onConfigurationSet=function(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[i.Validators.required,i.Validators.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-msg-count-config",template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.rpcReplyConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rpc-reply-config",template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.saveToCustomTableConfigForm},r.prototype.onConfigurationSet=function(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[i.Validators.required]],fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-custom-table-config",template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n \n \n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ne=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.translate=r,o.injector=n,o.fb=a,o.propagateChange=null,o.valueChangeSubscription=null,o}var a;return y(r,e),a=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){this.ngControl=this.injector.get(i.NgControl),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))},r.prototype.keyValsFormArray=function(){return this.kvListFormGroup.get("keyVals")},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t,r,n=this;this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();var a=[];if(e)try{for(var o=C(Object.keys(e)),l=o.next();!l.done;l=o.next()){var s=l.value;Object.prototype.hasOwnProperty.call(e,s)&&a.push(this.fb.group({key:[s,[i.Validators.required]],value:[e[s],[i.Validators.required]]}))}}catch(e){t={error:e}}finally{try{l&&!l.done&&(r=o.return)&&r.call(o)}finally{if(t)throw t.error}}this.kvListFormGroup.setControl("keyVals",this.fb.array(a)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((function(){n.updateModel()}))},r.prototype.removeKeyVal=function(e){this.kvListFormGroup.get("keyVals").removeAt(e)},r.prototype.addKeyVal=function(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[i.Validators.required]],value:["",[i.Validators.required]]}))},r.prototype.validate=function(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}},r.prototype.updateModel=function(){var e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{var t={};e.forEach((function(e){t[e.key]=e.value})),this.propagateChange(t)}},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:t.Injector},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",String)],r.prototype,"requiredText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"keyText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"keyRequiredText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"valText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"valRequiredText",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=a=b([t.Component({selector:"tb-kv-map-config",template:'
\n
\n {{ keyText }}\n {{ valText }}\n \n
\n
\n
\n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n \n
\n \n
\n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return a})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return a})),multi:!0}],styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:rgba(0,0,0,.54);font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}"]}),h("design:paramtypes",[o.Store,n.TranslateService,t.Injector,i.FormBuilder])],r)}(a.PageComponent),ae=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n.propagateChange=null,n}var n;return y(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[i.Validators.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((function(t){e.deviceRelationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=b([t.Component({selector:"tb-device-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-type
\n \n \n
device.device-types
\n \n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.propagateChange=null,n}var n;return y(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((function(t){e.relationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=b([t.Component({selector:"tb-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),ie=function(e){function r(t,r,n,o){var i,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.truncate=n,s.fb=o,s.placeholder="tb.rulenode.message-type",s.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],s.messageTypes=[],s.messageTypesList=[],s.searchText="",s.propagateChange=function(e){},s.messageTypeConfigForm=s.fb.group({messageType:[null]});try{for(var u=C(Object.keys(a.MessageType)),d=u.next();!d.done;d=u.next()){var p=d.value;s.messageTypesList.push({name:a.messageTypeNames.get(a.MessageType[p]),value:p})}}catch(e){i={error:e}}finally{try{d&&!d.done&&(l=u.return)&&l.call(u)}finally{if(i)throw i.error}}return s}var l;return y(r,e),l=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.ngOnInit=function(){var e=this;this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(t){return e.fetchMessageTypes(t)})),f.share())},r.prototype.ngAfterViewInit=function(){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t=this;this.searchText="",this.messageTypes.length=0,e&&e.forEach((function(e){var r=t.messageTypesList.find((function(t){return t.value===e}));r?t.messageTypes.push({name:r.name,value:r.value}):t.messageTypes.push({name:e,value:e})}))},r.prototype.displayMessageTypeFn=function(e){return e?e.name:void 0},r.prototype.textIsNotEmpty=function(e){return!!(e&&null!=e&&e.length>0)},r.prototype.createMessageType=function(e,t){e.preventDefault(),this.transformMessageType(t)},r.prototype.add=function(e){this.transformMessageType(e.value)},r.prototype.fetchMessageTypes=function(e){if(this.searchText=e,this.searchText&&this.searchText.length){var t=this.searchText.toUpperCase();return c.of(this.messageTypesList.filter((function(e){return e.name.toUpperCase().includes(t)})))}return c.of(this.messageTypesList)},r.prototype.transformMessageType=function(e){if((e||"").trim()){var t=null,r=e.trim(),n=this.messageTypesList.find((function(e){return e.name===r}));(t=n?{name:n.name,value:n.value}:{name:r,value:r})&&this.addMessageType(t)}this.clear("")},r.prototype.remove=function(e){var t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())},r.prototype.selected=function(e){this.addMessageType(e.option.value),this.clear("")},r.prototype.addMessageType=function(e){-1===this.messageTypes.findIndex((function(t){return t.value===e.value}))&&(this.messageTypes.push(e),this.updateModel())},r.prototype.onFocus=function(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((function(){t.messageTypeInput.nativeElement.blur(),t.messageTypeInput.nativeElement.focus()}),0)},r.prototype.updateModel=function(){var e=this.messageTypes.map((function(e){return e.value}));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:a.TruncatePipe},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),b([t.Input(),h("design:type",String)],r.prototype,"label",void 0),b([t.Input(),h("design:type",Object)],r.prototype,"placeholder",void 0),b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.ViewChild("chipList",{static:!1}),h("design:type",d.MatChipList)],r.prototype,"chipList",void 0),b([t.ViewChild("messageTypeAutocomplete",{static:!1}),h("design:type",p.MatAutocomplete)],r.prototype,"matAutocomplete",void 0),b([t.ViewChild("messageTypeInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"messageTypeInput",void 0),r=l=b([t.Component({selector:"tb-message-types-config",template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return l})),multi:!0}]}),h("design:paramtypes",[o.Store,n.TranslateService,a.TruncatePipe,i.FormBuilder])],r)}(a.PageComponent),le=function(){function e(){}return e=b([t.NgModule({declarations:[ne,ae,oe,ie],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule],exports:[ne,ae,oe,ie]})],e)}(),se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.unassignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-un-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),me=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.snsConfigForm},r.prototype.onConfigurationSet=function(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[i.Validators.required]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-sns-config",template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ue=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.sqsQueueType=H,n.sqsQueueTypes=Object.keys(H),n.sqsQueueTypeTranslationsMap=$,n}return y(r,e),r.prototype.configForm=function(){return this.sqsConfigForm},r.prototype.onConfigurationSet=function(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[i.Validators.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[i.Validators.required]],delaySeconds:[e?e.delaySeconds:null,[i.Validators.min(0),i.Validators.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-sqs-config",template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),de=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.pubSubConfigForm},r.prototype.onConfigurationSet=function(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[i.Validators.required]],topicName:[e?e.topicName:null,[i.Validators.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[i.Validators.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[i.Validators.required]],messageAttributes:[e?e.messageAttributes:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-pub-sub-config",template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.ackValues=["all","-1","0","1"],n.ToByteStandartCharsetTypesValues=Y,n.ToByteStandartCharsetTypeTranslationMap=Z,n}return y(r,e),r.prototype.configForm=function(){return this.kafkaConfigForm},r.prototype.onConfigurationSet=function(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],bootstrapServers:[e?e.bootstrapServers:null,[i.Validators.required]],retries:[e?e.retries:null,[i.Validators.min(0)]],batchSize:[e?e.batchSize:null,[i.Validators.min(0)]],linger:[e?e.linger:null,[i.Validators.min(0)]],bufferMemory:[e?e.bufferMemory:null,[i.Validators.min(0)]],acks:[e?e.acks:null,[i.Validators.required]],keySerializer:[e?e.keySerializer:null,[i.Validators.required]],valueSerializer:[e?e.valueSerializer:null,[i.Validators.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})},r.prototype.validatorTriggers=function(){return["addMetadataKeyValuesAsKafkaHeaders"]},r.prototype.updateValidators=function(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([i.Validators.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-kafka-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allMqttCredentialsTypes=Q,n.mqttCredentialsTypeTranslationsMap=_,n}return y(r,e),r.prototype.configForm=function(){return this.mqttConfigForm},r.prototype.onConfigurationSet=function(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[i.Validators.required]],username:[e&&e.credentials?e.credentials.username:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]]})})},r.prototype.prepareOutputConfig=function(e){var t=e.credentials.type;switch(t){case"anonymous":e.credentials={type:t};break;case"basic":e.credentials={type:t,username:e.credentials.username,password:e.credentials.password};break;case"cert.PEM":delete e.credentials.username}return e},r.prototype.validatorTriggers=function(){return["credentials.type"]},r.prototype.updateValidators=function(e){var t=this.mqttConfigForm.get("credentials"),r=t.get("type").value;switch(e&&t.reset({type:r},{emitEvent:!1}),t.get("username").setValidators([]),t.get("password").setValidators([]),t.get("caCert").setValidators([]),t.get("caCertFileName").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),r){case"anonymous":break;case"basic":t.get("username").setValidators([i.Validators.required]),t.get("password").setValidators([i.Validators.required]);break;case"cert.PEM":t.get("caCert").setValidators([i.Validators.required]),t.get("caCertFileName").setValidators([i.Validators.required]),t.get("privateKey").setValidators([i.Validators.required]),t.get("privateKeyFileName").setValidators([i.Validators.required]),t.get("cert").setValidators([i.Validators.required]),t.get("certFileName").setValidators([i.Validators.required])}t.get("username").updateValueAndValidity({emitEvent:e}),t.get("password").updateValueAndValidity({emitEvent:e}),t.get("caCert").updateValueAndValidity({emitEvent:e}),t.get("caCertFileName").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-mqtt-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n \n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n \n tb.rulenode.credentials\n \n {{ mqttCredentialsTypeTranslationsMap.get(mqttConfigForm.get(\'credentials\').get(\'type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ mqttCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],n}return y(r,e),r.prototype.configForm=function(){return this.rabbitMqConfigForm},r.prototype.onConfigurationSet=function(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[i.Validators.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[i.Validators.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rabbit-mq-config",template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.proxySchemes=["http","https"],n.httpRequestTypes=Object.keys(z),n}return y(r,e),r.prototype.configForm=function(){return this.restApiCallConfigForm},r.prototype.onConfigurationSet=function(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[i.Validators.required]],requestMethod:[e?e.requestMethod:null,[i.Validators.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[i.Validators.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]]})},r.prototype.validatorTriggers=function(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]},r.prototype.updateValidators=function(e){var t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,r=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,n=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;n&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(n?[i.Validators.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(n?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([i.Validators.min(0)])),r?this.restApiCallConfigForm.get("maxQueueSize").setValidators([i.Validators.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rest-api-call-config",template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n \n \n \n tb.rulenode.max-parallel-requests-count\n \n \n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ye=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.smtpProtocols=["smtp","smtps"],n.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"],n}return y(r,e),r.prototype.configForm=function(){return this.sendEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmtpSettings","enableProxy"]},r.prototype.updateValidators=function(e){var t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,r=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([i.Validators.required,i.Validators.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(r?[i.Validators.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(r?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-send-email-config",template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.serviceType=a.ServiceType.TB_RULE_ENGINE,n}return y(r,e),r.prototype.configForm=function(){return this.checkPointConfigForm},r.prototype.onConfigurationSet=function(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-check-point-config",template:'
\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),he=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allAzureIotHubCredentialsTypes=W,n.azureIotHubCredentialsTypeTranslationsMap=J,n}return y(r,e),r.prototype.configForm=function(){return this.azureIotHubConfigForm},r.prototype.onConfigurationSet=function(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[i.Validators.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[i.Validators.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})},r.prototype.prepareOutputConfig=function(e){var t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e},r.prototype.validatorTriggers=function(){return["credentials.type"]},r.prototype.updateValidators=function(e){var t=this.azureIotHubConfigForm.get("credentials"),r=t.get("type").value;switch(e&&t.reset({type:r},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),r){case"sas":t.get("sasKey").setValidators([i.Validators.required]);break;case"cert.PEM":t.get("privateKey").setValidators([i.Validators.required]),t.get("privateKeyFileName").setValidators([i.Validators.required]),t.get("cert").setValidators([i.Validators.required]),t.get("certFileName").setValidators([i.Validators.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-azure-iot-hub-config",template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.deviceProfile},r.prototype.onConfigurationSet=function(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,i.Validators.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,i.Validators.required]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-device-profile-config",template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.sendSmsConfigForm},r.prototype.onConfigurationSet=function(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[i.Validators.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[i.Validators.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmsSettings"]},r.prototype.updateValidators=function(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([i.Validators.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-send-sms-config",template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Fe=function(){function e(){}return e=b([t.NgModule({declarations:[x,T,q,S,I,k,N,V,E,A,L,X,ee,te,re,se,me,ue,de,pe,ce,fe,ge,ye,be,he,Ce,ve],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule,le],exports:[x,T,q,S,I,k,N,V,E,A,L,X,ee,te,re,se,me,ue,de,pe,ce,fe,ge,ye,be,he,Ce,ve]})],e)}(),xe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.checkMessageConfigForm},r.prototype.onConfigurationSet=function(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})},r.prototype.validateConfig=function(){var e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0},r.prototype.removeMessageName=function(e){var t=this.checkMessageConfigForm.get("messageNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))},r.prototype.removeMetadataName=function(e){var t=this.checkMessageConfigForm.get("metadataNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))},r.prototype.addMessageName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("messageNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("messageNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.prototype.addMetadataName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("metadataNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("metadataNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-check-message-config",template:'
\n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.entitySearchDirection=Object.keys(a.EntitySearchDirection),n.entitySearchDirectionTranslationsMap=a.entitySearchDirectionTranslations,n}return y(r,e),r.prototype.configForm=function(){return this.checkRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],relationType:[e?e.relationType:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["checkForSingleEntity"]},r.prototype.updateValidators=function(e){var t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-check-relation-config",template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),qe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=w,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=B,n}return y(r,e),r.prototype.configForm=function(){return this.geoFilterConfigForm},r.prototype.onConfigurationSet=function(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterType").setValidators([]):this.geoFilterConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoFilterConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoFilterConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.messageTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-message-type-config",template:'
\n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ie=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allowedEntityTypes=[a.EntityType.DEVICE,a.EntityType.ASSET,a.EntityType.ENTITY_VIEW,a.EntityType.TENANT,a.EntityType.CUSTOMER,a.EntityType.USER,a.EntityType.DASHBOARD,a.EntityType.RULE_CHAIN,a.EntityType.RULE_NODE],n}return y(r,e),r.prototype.configForm=function(){return this.originatorTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-originator-type-config",template:'
\n \n \n \n
\n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ke=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-filter-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Ne=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.switchConfigForm},r.prototype.onConfigurationSet=function(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.switchConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-filter-node-switch-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Ve=function(e){function r(t,r,n){var o,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.fb=n,s.alarmStatusTranslationsMap=a.alarmStatusTranslations,s.alarmStatusList=[],s.searchText="",s.displayStatusFn=s.displayStatus.bind(s);try{for(var m=C(Object.keys(a.AlarmStatus)),u=m.next();!u.done;u=m.next()){var d=u.value;s.alarmStatusList.push(a.AlarmStatus[d])}}catch(e){o={error:e}}finally{try{u&&!u.done&&(l=m.return)&&l.call(m)}finally{if(o)throw o.error}}return s.statusFormControl=new i.FormControl(""),s.filteredAlarmStatus=s.statusFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return s.fetchAlarmStatus(e)})),f.share()),s}return y(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.alarmStatusConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[i.Validators.required]]})},r.prototype.displayStatus=function(e){return e?this.translate.instant(a.alarmStatusTranslations.get(e)):void 0},r.prototype.fetchAlarmStatus=function(e){var t=this,r=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){var n=this.searchText.toUpperCase();return c.of(r.filter((function(e){return t.translate.instant(a.alarmStatusTranslations.get(a.AlarmStatus[e])).toUpperCase().includes(n)})))}return c.of(r)},r.prototype.alarmStatusSelected=function(e){this.addAlarmStatus(e.option.value),this.clear("")},r.prototype.removeAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}},r.prototype.addAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))},r.prototype.getAlarmStatusList=function(){var e=this;return this.alarmStatusList.filter((function(t){return-1===e.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(t)}))},r.prototype.onAlarmStatusInputFocus=function(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.alarmStatusInput.nativeElement.blur(),t.alarmStatusInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},b([t.ViewChild("alarmStatusInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"alarmStatusInput",void 0),r=b([t.Component({selector:"tb-filter-node-check-alarm-status-config",template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n'}),h("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ee=function(){function e(){}return e=b([t.NgModule({declarations:[xe,Te,qe,Se,Ie,ke,Ne,Ve],imports:[r.CommonModule,a.SharedModule,le],exports:[xe,Te,qe,Se,Ie,ke,Ne,Ve]})],e)}(),Ae=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.customerAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-customer-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Le=function(e){function r(t,r,n){var a,o,l=e.call(this,t)||this;l.store=t,l.translate=r,l.fb=n,l.entityDetailsTranslationsMap=G,l.entityDetailsList=[],l.searchText="",l.displayDetailsFn=l.displayDetails.bind(l);try{for(var s=C(Object.keys(K)),m=s.next();!m.done;m=s.next()){var u=m.value;l.entityDetailsList.push(K[u])}}catch(e){a={error:e}}finally{try{m&&!m.done&&(o=s.return)&&o.call(s)}finally{if(a)throw a.error}}return l.detailsFormControl=new i.FormControl(""),l.filteredEntityDetails=l.detailsFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return l.fetchEntityDetails(e)})),f.share()),l}return y(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.entityDetailsConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[i.Validators.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})},r.prototype.displayDetails=function(e){return e?this.translate.instant(G.get(e)):void 0},r.prototype.fetchEntityDetails=function(e){var t=this;if(this.searchText=e,this.searchText&&this.searchText.length){var r=this.searchText.toUpperCase();return c.of(this.entityDetailsList.filter((function(e){return t.translate.instant(G.get(K[e])).toUpperCase().includes(r)})))}return c.of(this.entityDetailsList)},r.prototype.detailsFieldSelected=function(e){this.addDetailsField(e.option.value),this.clear("")},r.prototype.removeDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}},r.prototype.addDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))},r.prototype.onEntityDetailsInputFocus=function(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.detailsInput.nativeElement.blur(),t.detailsInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},b([t.ViewChild("detailsInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"detailsInput",void 0),r=b([t.Component({selector:"tb-enrichment-node-entity-details-config",template:'
\n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-entity-details-matching\n
\n
\n
\n
\n
\n \n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
tb.rulenode.add-to-metadata-hint
\n
\n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}"]}),h("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Me=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.deviceAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[i.Validators.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.deviceAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.deviceAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.deviceAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.deviceAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-device-attributes-config",template:'
\n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.originatorAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.originatorAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.originatorAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.originatorAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.originatorAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-originator-attributes-config",template:'
\n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.originatorFieldsConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-originator-fields-config",template:'
\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),we=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n.fetchMode=U,n.fetchModes=Object.keys(U),n.samplingOrders=Object.keys(j),n.timeUnits=Object.keys(R),n.timeUnitsTranslationMap=D,n}return y(r,e),r.prototype.configForm=function(){return this.getTelemetryFromDatabaseConfigForm},r.prototype.onConfigurationSet=function(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],fetchMode:[e?e.fetchMode:null,[i.Validators.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchMode","useMetadataIntervalPatterns"]},r.prototype.updateValidators=function(e){var t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,r=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===U.ALL?(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([i.Validators.required,i.Validators.min(2),i.Validators.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),r?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([i.Validators.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})},r.prototype.removeKey=function(e,t){var r=this.getTelemetryFromDatabaseConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.getTelemetryFromDatabaseConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-get-telemetry-from-database",template:'
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
\n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
\n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-interval-patterns-hint
\n
\n
\n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.relatedAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[i.Validators.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-related-attributes-config",template:'
\n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),De=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.tenantAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-tenant-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ke=function(){function e(){}return e=b([t.NgModule({declarations:[Ae,Le,Me,Pe,Re,we,Oe,De],imports:[r.CommonModule,a.SharedModule,le],exports:[Ae,Le,Me,Pe,Re,we,Oe,De]})],e)}(),Be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.originatorSource=v,n.originatorSources=Object.keys(v),n.originatorSourceTranslationMap=P,n}return y(r,e),r.prototype.configForm=function(){return this.changeOriginatorConfigForm},r.prototype.onConfigurationSet=function(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[i.Validators.required]],relationsQuery:[e?e.relationsQuery:null,[]]})},r.prototype.validatorTriggers=function(){return["originatorSource"]},r.prototype.updateValidators=function(e){var t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===v.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([i.Validators.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-transformation-node-change-originator-config",template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ue=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-transformation-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),je=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.toEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[i.Validators.required]],toTemplate:[e?e.toTemplate:null,[i.Validators.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[i.Validators.required]],bodyTemplate:[e?e.bodyTemplate:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-transformation-node-to-email-config",template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),He=function(){function e(){}return e=b([t.NgModule({declarations:[Be,Ue,je],imports:[r.CommonModule,a.SharedModule,le],exports:[Be,Ue,je]})],e)}(),Ge=function(){function e(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-name-pattern-hint":"Name pattern, use ${metaKeyName} to substitute variables from metadata","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-type-pattern-hint":"Type pattern, use ${metaKeyName} to substitute variables from metadata","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-name-pattern-hint":"Customer name pattern, use ${metaKeyName} to substitute variables from metadata","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","client-attributes-hint":"Client attributes, use ${metaKeyName} to substitute variables from metadata","shared-attributes":"Shared attributes","shared-attributes-hint":"Shared attributes, use ${metaKeyName} to substitute variables from metadata","server-attributes":"Server attributes","server-attributes-hint":"Server attributes, use ${metaKeyName} to substitute variables from metadata","notify-device":"Notify Device","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","latest-timeseries":"Latest timeseries","latest-timeseries-hint":"Latest timeseries, use ${metaKeyName} to substitute variables from metadata","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-hint":"Relation type pattern, use ${metaKeyName} to substitute variables from metadata","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use metadata period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds metadata pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","period-in-seconds-pattern-hint":"Period in seconds pattern, use ${metaKeyName} to substitute variables from metadata","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","from-template-hint":"From address template, use ${metaKeyName} to substitute variables from metadata","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":"Comma separated address list, use ${metaKeyName} to substitute variables from metadata","cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","subject-template-hint":"Mail subject template, use ${metaKeyName} to substitute variables from metadata","body-template":"Body Template","body-template-required":"Body Template is required","body-template-hint":"Mail body template, use ${metaKeyName} to substitute variables from metadata","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","endpoint-url-pattern-hint":"HTTP URL address pattern, use ${metaKeyName} to substitute variables from metadata","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":"Use ${metaKeyName} in header/value fields to substitute variables from metadata",header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required","mqtt-topic-pattern-hint":"MQTT topic pattern, use ${metaKeyName} to substitute variables from metadata",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","topic-arn-pattern-hint":"Topic ARN pattern, use ${metaKeyName} to substitute variables from metadata","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","queue-url-pattern-hint":"Queue URL pattern, use ${metaKeyName} to substitute variables from metadata","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":"Use ${metaKeyName} in name/value fields to substitute variables from metadata","connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"CA certificate file *","private-key":"Private key file *",cert:"Certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use metadata interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","start-interval-pattern-hint":"Start interval pattern, use ${metaKeyName} to substitute variables from metadata","end-interval-pattern-hint":"End interval pattern, use ${metaKeyName} to substitute variables from metadata","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":"Comma separated Phone Numbers, use ${metaKeyName} to substitute variables from metadata","sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","sms-message-template-hint":"SMS message template, use ${metaKeyName} to substitute variables from metadata","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-zip":"Zip","entity-details-address":"Address","entity-details-address2":"Address2","entity-details-additional_info":"Additional Info","entity-details-phone":"Phone","entity-details-email":"Email","add-to-metadata":"Add selected details to message metadata","add-to-metadata-hint":"If selected, adds the selected details keys to the message metadata instead of message data.","entity-details-list-empty":"No entity details selected.","no-entity-details-matching":"No entity details matching were found.","custom-table-name":"Custom table name","custom-table-name-required":"Table Name is required","custom-table-hint":"You should enter the table name without prefix 'cs_tb_'.","message-field":"Message field","message-field-required":"Message field is required.","table-col":"Table column","table-col-required":"Table column is required.","latitude-key-name":"Latitude key name","longitude-key-name":"Longitude key name","latitude-key-name-required":"Latitude key name is required.","longitude-key-name-required":"Longitude key name is required.","fetch-perimeter-info-from-message-metadata":"Fetch perimeter information from message metadata","perimeter-circle":"Circle","perimeter-polygon":"Polygon","perimeter-type":"Perimeter type","circle-center-latitude":"Center latitude","circle-center-latitude-required":"Center latitude is required.","circle-center-longitude":"Center longitude","circle-center-longitude-required":"Center longitude is required.","range-unit-meter":"Meter","range-unit-kilometer":"Kilometer","range-unit-foot":"Foot","range-unit-mile":"Mile","range-unit-nautical-mile":"Nautical mile","range-units":"Range units",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].","min-inside-duration":"Minimal inside duration","min-inside-duration-value-required":"Minimal inside duration is required","min-inside-duration-time-unit":"Minimal inside duration time unit","min-outside-duration":"Minimal outside duration","min-outside-duration-value-required":"Minimal outside duration is required","min-outside-duration-time-unit":"Minimal outside duration time unit","tell-failure-if-absent":"Tell Failure","tell-failure-if-absent-hint":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"get-latest-value-with-ts":"Fetch Latest telemetry with Timestamp","get-latest-value-with-ts-hint":'If selected, latest telemetry values will be added to the outbound message metadata with timestamp, e.g: "temp": "{\\"ts\\":1574329385897,\\"value\\":42}"',"use-redis-queue":"Use redis queue for message persistence","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules"},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"}}},!0)}(e)}return e.ctorParameters=function(){return[{type:n.TranslateService}]},e=b([t.NgModule({declarations:[F],imports:[r.CommonModule,a.SharedModule],exports:[Fe,Ee,Ke,He,F]}),h("design:paramtypes",[n.TranslateService])],e)}();e.RuleNodeCoreConfigModule=Ge,e.ɵa=F,e.ɵb=Fe,e.ɵba=be,e.ɵbb=he,e.ɵbc=Ce,e.ɵbd=ve,e.ɵbe=le,e.ɵbf=ne,e.ɵbg=ae,e.ɵbh=oe,e.ɵbi=ie,e.ɵbj=Ee,e.ɵbk=xe,e.ɵbl=Te,e.ɵbm=qe,e.ɵbn=Se,e.ɵbo=Ie,e.ɵbp=ke,e.ɵbq=Ne,e.ɵbr=Ve,e.ɵbs=Ke,e.ɵbt=Ae,e.ɵbu=Le,e.ɵbv=Me,e.ɵbw=Pe,e.ɵbx=Re,e.ɵby=we,e.ɵbz=Oe,e.ɵc=x,e.ɵca=De,e.ɵcb=He,e.ɵcc=Be,e.ɵcd=Ue,e.ɵce=je,e.ɵd=T,e.ɵe=q,e.ɵf=S,e.ɵg=I,e.ɵh=k,e.ɵi=N,e.ɵj=V,e.ɵk=E,e.ɵl=A,e.ɵm=L,e.ɵn=X,e.ɵo=ee,e.ɵp=te,e.ɵq=re,e.ɵr=se,e.ɵs=me,e.ɵt=ue,e.ɵu=de,e.ɵv=pe,e.ɵw=ce,e.ɵx=fe,e.ɵy=ge,e.ɵz=ye,Object.defineProperty(e,"__esModule",{value:!0})})); + ***************************************************************************** */var g=function(e,t){return(g=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])})(e,t)};function y(e,t){function r(){this.constructor=e}g(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}function b(e,t,r,n){var a,o=arguments.length,i=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,r,n);else for(var l=e.length-1;l>=0;l--)(a=e[l])&&(i=(o<3?a(i):o>3?a(t,r,i):a(t,r))||i);return o>3&&i&&Object.defineProperty(t,r,i),i}function h(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}Object.create;function C(e){var t="function"==typeof Symbol&&Symbol.iterator,r=t&&e[t],n=0;if(r)return r.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}Object.create;var v,F=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.emptyConfigForm},r.prototype.onConfigurationSet=function(e){this.emptyConfigForm=this.fb.group({})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-node-empty-config",template:"
"}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),x=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return y(r,e),r.prototype.configForm=function(){return this.attributesConfigForm},r.prototype.onConfigurationSet=function(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]],notifyDevice:[!e||e.scope,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-attributes-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),T=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.timeseriesConfigForm},r.prototype.onConfigurationSet=function(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-timeseries-config",template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),q=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.rpcRequestConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rpc-request-config",template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),S=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.logConfigForm},r.prototype.onConfigurationSet=function(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.logConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-log-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),I=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.assignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),k=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.clearAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],alarmType:[e?e.alarmType:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-clear-alarm-config",template:'
\n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),N=function(e){function r(t,r,n,o){var i=e.call(this,t)||this;return i.store=t,i.fb=r,i.nodeScriptTestService=n,i.translate=o,i.alarmSeverities=Object.keys(a.AlarmSeverity),i.alarmSeverityTranslationMap=a.alarmSeverityTranslations,i.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],i}return y(r,e),r.prototype.configForm=function(){return this.createAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]]})},r.prototype.validatorTriggers=function(){return["useMessageAlarmData"]},r.prototype.updateValidators=function(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([i.Validators.required]),this.createAlarmConfigForm.get("severity").setValidators([i.Validators.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})},r.prototype.testScript=function(){var e=this,t=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.removeKey=function(e,t){var r=this.createAlarmConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.createAlarmConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.createAlarmConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.createAlarmConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-create-alarm-config",template:'
\n \n \n \n
\n \n
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n \n \n
\n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),V=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return y(r,e),r.prototype.configForm=function(){return this.createRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[i.Validators.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["entityType"]},r.prototype.updateValidators=function(e){var t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==a.EntityType.DEVICE&&t!==a.EntityType.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([i.Validators.required]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-create-relation-config",template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),E=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.msgDelayConfigForm},r.prototype.onConfigurationSet=function(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(1e5)]]})},r.prototype.validatorTriggers=function(){return["useMetadataPeriodInSecondsPatterns"]},r.prototype.updateValidators=function(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([i.Validators.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([i.Validators.required,i.Validators.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-msg-delay-config",template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),A=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return y(r,e),r.prototype.configForm=function(){return this.deleteRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["deleteForSingleEntity","entityType"]},r.prototype.updateValidators=function(e){var t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,r=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&r?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-delete-relation-config",template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),L=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.generatorConfigForm},r.prototype.onConfigurationSet=function(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[i.Validators.required,i.Validators.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[i.Validators.required,i.Validators.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.prepareInputConfig=function(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e},r.prototype.prepareOutputConfig=function(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e},r.prototype.testScript=function(){var e=this,t=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId).subscribe((function(t){t&&e.generatorConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-generator-config",template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent);!function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(v||(v={}));var M,P=new Map([[v.CUSTOMER,"tb.rulenode.originator-customer"],[v.TENANT,"tb.rulenode.originator-tenant"],[v.RELATED,"tb.rulenode.originator-related"],[v.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(M||(M={}));var R,w=new Map([[M.CIRCLE,"tb.rulenode.perimeter-circle"],[M.POLYGON,"tb.rulenode.perimeter-polygon"]]);!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(R||(R={}));var O,D=new Map([[R.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[R.SECONDS,"tb.rulenode.time-unit-seconds"],[R.MINUTES,"tb.rulenode.time-unit-minutes"],[R.HOURS,"tb.rulenode.time-unit-hours"],[R.DAYS,"tb.rulenode.time-unit-days"]]);!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(O||(O={}));var K,B=new Map([[O.METER,"tb.rulenode.range-unit-meter"],[O.KILOMETER,"tb.rulenode.range-unit-kilometer"],[O.FOOT,"tb.rulenode.range-unit-foot"],[O.MILE,"tb.rulenode.range-unit-mile"],[O.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(K||(K={}));var G,U,j,H=new Map([[K.TITLE,"tb.rulenode.entity-details-title"],[K.COUNTRY,"tb.rulenode.entity-details-country"],[K.STATE,"tb.rulenode.entity-details-state"],[K.ZIP,"tb.rulenode.entity-details-zip"],[K.ADDRESS,"tb.rulenode.entity-details-address"],[K.ADDRESS2,"tb.rulenode.entity-details-address2"],[K.PHONE,"tb.rulenode.entity-details-phone"],[K.EMAIL,"tb.rulenode.entity-details-email"],[K.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(G||(G={})),function(e){e.ASC="ASC",e.DESC="DESC"}(U||(U={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(j||(j={}));var z,$=new Map([[j.STANDARD,"tb.rulenode.sqs-queue-standard"],[j.FIFO,"tb.rulenode.sqs-queue-fifo"]]),Q=["anonymous","basic","cert.PEM"],_=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),W=["sas","cert.PEM"],J=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(z||(z={}));var Y=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],Z=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]),X=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=w,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=B,n.timeUnits=Object.keys(R),n.timeUnitsTranslationMap=D,n}return y(r,e),r.prototype.configForm=function(){return this.geoActionConfigForm},r.prototype.onConfigurationSet=function(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[i.Validators.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterType").setValidators([]):this.geoActionConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoActionConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoActionConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.msgCountConfigForm},r.prototype.onConfigurationSet=function(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[i.Validators.required,i.Validators.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-msg-count-config",template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.rpcReplyConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rpc-reply-config",template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.saveToCustomTableConfigForm},r.prototype.onConfigurationSet=function(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[i.Validators.required]],fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-custom-table-config",template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n \n \n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ne=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.translate=r,o.injector=n,o.fb=a,o.propagateChange=null,o.valueChangeSubscription=null,o}var a;return y(r,e),a=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){this.ngControl=this.injector.get(i.NgControl),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))},r.prototype.keyValsFormArray=function(){return this.kvListFormGroup.get("keyVals")},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t,r,n=this;this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();var a=[];if(e)try{for(var o=C(Object.keys(e)),l=o.next();!l.done;l=o.next()){var s=l.value;Object.prototype.hasOwnProperty.call(e,s)&&a.push(this.fb.group({key:[s,[i.Validators.required]],value:[e[s],[i.Validators.required]]}))}}catch(e){t={error:e}}finally{try{l&&!l.done&&(r=o.return)&&r.call(o)}finally{if(t)throw t.error}}this.kvListFormGroup.setControl("keyVals",this.fb.array(a)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((function(){n.updateModel()}))},r.prototype.removeKeyVal=function(e){this.kvListFormGroup.get("keyVals").removeAt(e)},r.prototype.addKeyVal=function(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[i.Validators.required]],value:["",[i.Validators.required]]}))},r.prototype.validate=function(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}},r.prototype.updateModel=function(){var e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{var t={};e.forEach((function(e){t[e.key]=e.value})),this.propagateChange(t)}},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:t.Injector},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",String)],r.prototype,"requiredText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"keyText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"keyRequiredText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"valText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"valRequiredText",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=a=b([t.Component({selector:"tb-kv-map-config",template:'
\n
\n {{ keyText }}\n {{ valText }}\n \n
\n
\n
\n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n \n
\n \n
\n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return a})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return a})),multi:!0}],styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:rgba(0,0,0,.54);font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}"]}),h("design:paramtypes",[o.Store,n.TranslateService,t.Injector,i.FormBuilder])],r)}(a.PageComponent),ae=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n.propagateChange=null,n}var n;return y(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[i.Validators.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((function(t){e.deviceRelationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=b([t.Component({selector:"tb-device-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-type
\n \n \n
device.device-types
\n \n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.propagateChange=null,n}var n;return y(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((function(t){e.relationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=b([t.Component({selector:"tb-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),ie=function(e){function r(t,r,n,o){var i,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.truncate=n,s.fb=o,s.placeholder="tb.rulenode.message-type",s.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],s.messageTypes=[],s.messageTypesList=[],s.searchText="",s.propagateChange=function(e){},s.messageTypeConfigForm=s.fb.group({messageType:[null]});try{for(var u=C(Object.keys(a.MessageType)),d=u.next();!d.done;d=u.next()){var p=d.value;s.messageTypesList.push({name:a.messageTypeNames.get(a.MessageType[p]),value:p})}}catch(e){i={error:e}}finally{try{d&&!d.done&&(l=u.return)&&l.call(u)}finally{if(i)throw i.error}}return s}var l;return y(r,e),l=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.ngOnInit=function(){var e=this;this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(t){return e.fetchMessageTypes(t)})),f.share())},r.prototype.ngAfterViewInit=function(){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t=this;this.searchText="",this.messageTypes.length=0,e&&e.forEach((function(e){var r=t.messageTypesList.find((function(t){return t.value===e}));r?t.messageTypes.push({name:r.name,value:r.value}):t.messageTypes.push({name:e,value:e})}))},r.prototype.displayMessageTypeFn=function(e){return e?e.name:void 0},r.prototype.textIsNotEmpty=function(e){return!!(e&&null!=e&&e.length>0)},r.prototype.createMessageType=function(e,t){e.preventDefault(),this.transformMessageType(t)},r.prototype.add=function(e){this.transformMessageType(e.value)},r.prototype.fetchMessageTypes=function(e){if(this.searchText=e,this.searchText&&this.searchText.length){var t=this.searchText.toUpperCase();return c.of(this.messageTypesList.filter((function(e){return e.name.toUpperCase().includes(t)})))}return c.of(this.messageTypesList)},r.prototype.transformMessageType=function(e){if((e||"").trim()){var t=null,r=e.trim(),n=this.messageTypesList.find((function(e){return e.name===r}));(t=n?{name:n.name,value:n.value}:{name:r,value:r})&&this.addMessageType(t)}this.clear("")},r.prototype.remove=function(e){var t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())},r.prototype.selected=function(e){this.addMessageType(e.option.value),this.clear("")},r.prototype.addMessageType=function(e){-1===this.messageTypes.findIndex((function(t){return t.value===e.value}))&&(this.messageTypes.push(e),this.updateModel())},r.prototype.onFocus=function(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((function(){t.messageTypeInput.nativeElement.blur(),t.messageTypeInput.nativeElement.focus()}),0)},r.prototype.updateModel=function(){var e=this.messageTypes.map((function(e){return e.value}));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:a.TruncatePipe},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),b([t.Input(),h("design:type",String)],r.prototype,"label",void 0),b([t.Input(),h("design:type",Object)],r.prototype,"placeholder",void 0),b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.ViewChild("chipList",{static:!1}),h("design:type",d.MatChipList)],r.prototype,"chipList",void 0),b([t.ViewChild("messageTypeAutocomplete",{static:!1}),h("design:type",p.MatAutocomplete)],r.prototype,"matAutocomplete",void 0),b([t.ViewChild("messageTypeInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"messageTypeInput",void 0),r=l=b([t.Component({selector:"tb-message-types-config",template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return l})),multi:!0}]}),h("design:paramtypes",[o.Store,n.TranslateService,a.TruncatePipe,i.FormBuilder])],r)}(a.PageComponent),le=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.subscriptions=[],n.allCredentialsTypes=Q,n.credentialsTypeTranslationsMap=_,n.propagateChange=null,n}var n;return y(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.credentialsConfigFormGroup=this.fb.group({type:[null,[i.Validators.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(f.distinctUntilChanged()).subscribe((function(){e.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((function(){e.credentialsTypeChanged()})))},r.prototype.ngOnDestroy=function(){this.subscriptions.forEach((function(e){return e.unsubscribe()}))},r.prototype.writeValue=function(e){s.isDefinedAndNotNull(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))},r.prototype.setDisabledState=function(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())},r.prototype.updateView=function(){var e=this.credentialsConfigFormGroup.value,t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.validate=function(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}},r.prototype.credentialsTypeChanged=function(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()},r.prototype.updateValidators=function(e){void 0===e&&(e=!1);var t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([i.Validators.required]),this.credentialsConfigFormGroup.get("password").setValidators([i.Validators.required]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(i.Validators.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})},r.prototype.requiredFilesSelected=function(e,t){return void 0===t&&(t=null),function(r){return t||(t=[Object.keys(r.controls)]),(null==r?void 0:r.controls)&&t.some((function(t){return t.every((function(t){return!e(r.controls[t])}))}))?null:{notAllRequiredFilesSelected:!0}}},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=b([t.Component({selector:"tb-credentials-config",template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n
\n
\n
\n
\n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),se=function(){function e(){}return e=b([t.NgModule({declarations:[ne,ae,oe,ie,le],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule],exports:[ne,ae,oe,ie,le]})],e)}(),me=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.unassignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-un-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ue=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.snsConfigForm},r.prototype.onConfigurationSet=function(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[i.Validators.required]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-sns-config",template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),de=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.sqsQueueType=j,n.sqsQueueTypes=Object.keys(j),n.sqsQueueTypeTranslationsMap=$,n}return y(r,e),r.prototype.configForm=function(){return this.sqsConfigForm},r.prototype.onConfigurationSet=function(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[i.Validators.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[i.Validators.required]],delaySeconds:[e?e.delaySeconds:null,[i.Validators.min(0),i.Validators.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-sqs-config",template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.pubSubConfigForm},r.prototype.onConfigurationSet=function(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[i.Validators.required]],topicName:[e?e.topicName:null,[i.Validators.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[i.Validators.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[i.Validators.required]],messageAttributes:[e?e.messageAttributes:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-pub-sub-config",template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.ackValues=["all","-1","0","1"],n.ToByteStandartCharsetTypesValues=Y,n.ToByteStandartCharsetTypeTranslationMap=Z,n}return y(r,e),r.prototype.configForm=function(){return this.kafkaConfigForm},r.prototype.onConfigurationSet=function(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],bootstrapServers:[e?e.bootstrapServers:null,[i.Validators.required]],retries:[e?e.retries:null,[i.Validators.min(0)]],batchSize:[e?e.batchSize:null,[i.Validators.min(0)]],linger:[e?e.linger:null,[i.Validators.min(0)]],bufferMemory:[e?e.bufferMemory:null,[i.Validators.min(0)]],acks:[e?e.acks:null,[i.Validators.required]],keySerializer:[e?e.keySerializer:null,[i.Validators.required]],valueSerializer:[e?e.valueSerializer:null,[i.Validators.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})},r.prototype.validatorTriggers=function(){return["addMetadataKeyValuesAsKafkaHeaders"]},r.prototype.updateValidators=function(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([i.Validators.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-kafka-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.mqttConfigForm},r.prototype.onConfigurationSet=function(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-mqtt-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n \n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],n}return y(r,e),r.prototype.configForm=function(){return this.rabbitMqConfigForm},r.prototype.onConfigurationSet=function(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[i.Validators.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[i.Validators.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rabbit-mq-config",template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ye=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.proxySchemes=["http","https"],n.httpRequestTypes=Object.keys(z),n}return y(r,e),r.prototype.configForm=function(){return this.restApiCallConfigForm},r.prototype.onConfigurationSet=function(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[i.Validators.required]],requestMethod:[e?e.requestMethod:null,[i.Validators.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[i.Validators.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})},r.prototype.validatorTriggers=function(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]},r.prototype.updateValidators=function(e){var t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,r=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,n=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;n&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(n?[i.Validators.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(n?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([i.Validators.min(0)])),r?this.restApiCallConfigForm.get("maxQueueSize").setValidators([i.Validators.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rest-api-call-config",template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n \n \n \n tb.rulenode.max-parallel-requests-count\n \n \n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.smtpProtocols=["smtp","smtps"],n.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"],n}return y(r,e),r.prototype.configForm=function(){return this.sendEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmtpSettings","enableProxy"]},r.prototype.updateValidators=function(e){var t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,r=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([i.Validators.required,i.Validators.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(r?[i.Validators.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(r?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-send-email-config",template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),he=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.serviceType=a.ServiceType.TB_RULE_ENGINE,n}return y(r,e),r.prototype.configForm=function(){return this.checkPointConfigForm},r.prototype.onConfigurationSet=function(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-check-point-config",template:'
\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allAzureIotHubCredentialsTypes=W,n.azureIotHubCredentialsTypeTranslationsMap=J,n}return y(r,e),r.prototype.configForm=function(){return this.azureIotHubConfigForm},r.prototype.onConfigurationSet=function(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[i.Validators.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[i.Validators.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})},r.prototype.prepareOutputConfig=function(e){var t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e},r.prototype.validatorTriggers=function(){return["credentials.type"]},r.prototype.updateValidators=function(e){var t=this.azureIotHubConfigForm.get("credentials"),r=t.get("type").value;switch(e&&t.reset({type:r},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),r){case"sas":t.get("sasKey").setValidators([i.Validators.required]);break;case"cert.PEM":t.get("privateKey").setValidators([i.Validators.required]),t.get("privateKeyFileName").setValidators([i.Validators.required]),t.get("cert").setValidators([i.Validators.required]),t.get("certFileName").setValidators([i.Validators.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-azure-iot-hub-config",template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.deviceProfile},r.prototype.onConfigurationSet=function(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,i.Validators.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,i.Validators.required]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-device-profile-config",template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.sendSmsConfigForm},r.prototype.onConfigurationSet=function(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[i.Validators.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[i.Validators.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmsSettings"]},r.prototype.updateValidators=function(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([i.Validators.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-send-sms-config",template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),xe=function(){function e(){}return e=b([t.NgModule({declarations:[x,T,q,S,I,k,N,V,E,A,L,X,ee,te,re,me,ue,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule,se],exports:[x,T,q,S,I,k,N,V,E,A,L,X,ee,te,re,me,ue,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe]})],e)}(),Te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.checkMessageConfigForm},r.prototype.onConfigurationSet=function(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})},r.prototype.validateConfig=function(){var e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0},r.prototype.removeMessageName=function(e){var t=this.checkMessageConfigForm.get("messageNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))},r.prototype.removeMetadataName=function(e){var t=this.checkMessageConfigForm.get("metadataNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))},r.prototype.addMessageName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("messageNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("messageNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.prototype.addMetadataName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("metadataNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("metadataNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-check-message-config",template:'
\n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),qe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.entitySearchDirection=Object.keys(a.EntitySearchDirection),n.entitySearchDirectionTranslationsMap=a.entitySearchDirectionTranslations,n}return y(r,e),r.prototype.configForm=function(){return this.checkRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],relationType:[e?e.relationType:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["checkForSingleEntity"]},r.prototype.updateValidators=function(e){var t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-check-relation-config",template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=w,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=B,n}return y(r,e),r.prototype.configForm=function(){return this.geoFilterConfigForm},r.prototype.onConfigurationSet=function(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterType").setValidators([]):this.geoFilterConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoFilterConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoFilterConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ie=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.messageTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-message-type-config",template:'
\n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allowedEntityTypes=[a.EntityType.DEVICE,a.EntityType.ASSET,a.EntityType.ENTITY_VIEW,a.EntityType.TENANT,a.EntityType.CUSTOMER,a.EntityType.USER,a.EntityType.DASHBOARD,a.EntityType.RULE_CHAIN,a.EntityType.RULE_NODE],n}return y(r,e),r.prototype.configForm=function(){return this.originatorTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-originator-type-config",template:'
\n \n \n \n
\n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ne=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-filter-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Ve=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.switchConfigForm},r.prototype.onConfigurationSet=function(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.switchConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-filter-node-switch-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Ee=function(e){function r(t,r,n){var o,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.fb=n,s.alarmStatusTranslationsMap=a.alarmStatusTranslations,s.alarmStatusList=[],s.searchText="",s.displayStatusFn=s.displayStatus.bind(s);try{for(var m=C(Object.keys(a.AlarmStatus)),u=m.next();!u.done;u=m.next()){var d=u.value;s.alarmStatusList.push(a.AlarmStatus[d])}}catch(e){o={error:e}}finally{try{u&&!u.done&&(l=m.return)&&l.call(m)}finally{if(o)throw o.error}}return s.statusFormControl=new i.FormControl(""),s.filteredAlarmStatus=s.statusFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return s.fetchAlarmStatus(e)})),f.share()),s}return y(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.alarmStatusConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[i.Validators.required]]})},r.prototype.displayStatus=function(e){return e?this.translate.instant(a.alarmStatusTranslations.get(e)):void 0},r.prototype.fetchAlarmStatus=function(e){var t=this,r=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){var n=this.searchText.toUpperCase();return c.of(r.filter((function(e){return t.translate.instant(a.alarmStatusTranslations.get(a.AlarmStatus[e])).toUpperCase().includes(n)})))}return c.of(r)},r.prototype.alarmStatusSelected=function(e){this.addAlarmStatus(e.option.value),this.clear("")},r.prototype.removeAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}},r.prototype.addAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))},r.prototype.getAlarmStatusList=function(){var e=this;return this.alarmStatusList.filter((function(t){return-1===e.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(t)}))},r.prototype.onAlarmStatusInputFocus=function(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.alarmStatusInput.nativeElement.blur(),t.alarmStatusInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},b([t.ViewChild("alarmStatusInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"alarmStatusInput",void 0),r=b([t.Component({selector:"tb-filter-node-check-alarm-status-config",template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n'}),h("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ae=function(){function e(){}return e=b([t.NgModule({declarations:[Te,qe,Se,Ie,ke,Ne,Ve,Ee],imports:[r.CommonModule,a.SharedModule,se],exports:[Te,qe,Se,Ie,ke,Ne,Ve,Ee]})],e)}(),Le=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.customerAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-customer-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Me=function(e){function r(t,r,n){var a,o,l=e.call(this,t)||this;l.store=t,l.translate=r,l.fb=n,l.entityDetailsTranslationsMap=H,l.entityDetailsList=[],l.searchText="",l.displayDetailsFn=l.displayDetails.bind(l);try{for(var s=C(Object.keys(K)),m=s.next();!m.done;m=s.next()){var u=m.value;l.entityDetailsList.push(K[u])}}catch(e){a={error:e}}finally{try{m&&!m.done&&(o=s.return)&&o.call(s)}finally{if(a)throw a.error}}return l.detailsFormControl=new i.FormControl(""),l.filteredEntityDetails=l.detailsFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return l.fetchEntityDetails(e)})),f.share()),l}return y(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.entityDetailsConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[i.Validators.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})},r.prototype.displayDetails=function(e){return e?this.translate.instant(H.get(e)):void 0},r.prototype.fetchEntityDetails=function(e){var t=this;if(this.searchText=e,this.searchText&&this.searchText.length){var r=this.searchText.toUpperCase();return c.of(this.entityDetailsList.filter((function(e){return t.translate.instant(H.get(K[e])).toUpperCase().includes(r)})))}return c.of(this.entityDetailsList)},r.prototype.detailsFieldSelected=function(e){this.addDetailsField(e.option.value),this.clear("")},r.prototype.removeDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}},r.prototype.addDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))},r.prototype.onEntityDetailsInputFocus=function(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.detailsInput.nativeElement.blur(),t.detailsInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},b([t.ViewChild("detailsInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"detailsInput",void 0),r=b([t.Component({selector:"tb-enrichment-node-entity-details-config",template:'
\n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-entity-details-matching\n
\n
\n
\n
\n
\n \n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
tb.rulenode.add-to-metadata-hint
\n
\n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}"]}),h("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.deviceAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[i.Validators.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.deviceAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.deviceAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.deviceAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.deviceAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-device-attributes-config",template:'
\n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.originatorAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.originatorAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.originatorAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.originatorAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.originatorAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-originator-attributes-config",template:'
\n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),we=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.originatorFieldsConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-originator-fields-config",template:'
\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n.fetchMode=G,n.fetchModes=Object.keys(G),n.samplingOrders=Object.keys(U),n.timeUnits=Object.keys(R),n.timeUnitsTranslationMap=D,n}return y(r,e),r.prototype.configForm=function(){return this.getTelemetryFromDatabaseConfigForm},r.prototype.onConfigurationSet=function(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],fetchMode:[e?e.fetchMode:null,[i.Validators.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchMode","useMetadataIntervalPatterns"]},r.prototype.updateValidators=function(e){var t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,r=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===G.ALL?(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([i.Validators.required,i.Validators.min(2),i.Validators.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),r?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([i.Validators.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})},r.prototype.removeKey=function(e,t){var r=this.getTelemetryFromDatabaseConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.getTelemetryFromDatabaseConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-get-telemetry-from-database",template:'
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
\n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
\n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-interval-patterns-hint
\n
\n
\n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),De=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.relatedAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[i.Validators.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-related-attributes-config",template:'
\n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.tenantAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-tenant-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Be=function(){function e(){}return e=b([t.NgModule({declarations:[Le,Me,Pe,Re,we,Oe,De,Ke],imports:[r.CommonModule,a.SharedModule,se],exports:[Le,Me,Pe,Re,we,Oe,De,Ke]})],e)}(),Ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.originatorSource=v,n.originatorSources=Object.keys(v),n.originatorSourceTranslationMap=P,n}return y(r,e),r.prototype.configForm=function(){return this.changeOriginatorConfigForm},r.prototype.onConfigurationSet=function(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[i.Validators.required]],relationsQuery:[e?e.relationsQuery:null,[]]})},r.prototype.validatorTriggers=function(){return["originatorSource"]},r.prototype.updateValidators=function(e){var t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===v.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([i.Validators.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-transformation-node-change-originator-config",template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ue=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-transformation-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),je=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.toEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[i.Validators.required]],toTemplate:[e?e.toTemplate:null,[i.Validators.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[i.Validators.required]],bodyTemplate:[e?e.bodyTemplate:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-transformation-node-to-email-config",template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),He=function(){function e(){}return e=b([t.NgModule({declarations:[Ge,Ue,je],imports:[r.CommonModule,a.SharedModule,se],exports:[Ge,Ue,je]})],e)}(),ze=function(){function e(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-name-pattern-hint":"Name pattern, use ${metaKeyName} to substitute variables from metadata","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-type-pattern-hint":"Type pattern, use ${metaKeyName} to substitute variables from metadata","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-name-pattern-hint":"Customer name pattern, use ${metaKeyName} to substitute variables from metadata","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","client-attributes-hint":"Client attributes, use ${metaKeyName} to substitute variables from metadata","shared-attributes":"Shared attributes","shared-attributes-hint":"Shared attributes, use ${metaKeyName} to substitute variables from metadata","server-attributes":"Server attributes","server-attributes-hint":"Server attributes, use ${metaKeyName} to substitute variables from metadata","notify-device":"Notify Device","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","latest-timeseries":"Latest timeseries","latest-timeseries-hint":"Latest timeseries, use ${metaKeyName} to substitute variables from metadata","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-hint":"Relation type pattern, use ${metaKeyName} to substitute variables from metadata","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use metadata period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds metadata pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","period-in-seconds-pattern-hint":"Period in seconds pattern, use ${metaKeyName} to substitute variables from metadata","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","from-template-hint":"From address template, use ${metaKeyName} to substitute variables from metadata","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":"Comma separated address list, use ${metaKeyName} to substitute variables from metadata","cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","subject-template-hint":"Mail subject template, use ${metaKeyName} to substitute variables from metadata","body-template":"Body Template","body-template-required":"Body Template is required","body-template-hint":"Mail body template, use ${metaKeyName} to substitute variables from metadata","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","endpoint-url-pattern-hint":"HTTP URL address pattern, use ${metaKeyName} to substitute variables from metadata","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":"Use ${metaKeyName} in header/value fields to substitute variables from metadata",header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required","mqtt-topic-pattern-hint":"MQTT topic pattern, use ${metaKeyName} to substitute variables from metadata",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","topic-arn-pattern-hint":"Topic ARN pattern, use ${metaKeyName} to substitute variables from metadata","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","queue-url-pattern-hint":"Queue URL pattern, use ${metaKeyName} to substitute variables from metadata","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":"Use ${metaKeyName} in name/value fields to substitute variables from metadata","connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file *","private-key":"Client private key file *",cert:"Client certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use metadata interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","start-interval-pattern-hint":"Start interval pattern, use ${metaKeyName} to substitute variables from metadata","end-interval-pattern-hint":"End interval pattern, use ${metaKeyName} to substitute variables from metadata","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":"Comma separated Phone Numbers, use ${metaKeyName} to substitute variables from metadata","sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","sms-message-template-hint":"SMS message template, use ${metaKeyName} to substitute variables from metadata","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-zip":"Zip","entity-details-address":"Address","entity-details-address2":"Address2","entity-details-additional_info":"Additional Info","entity-details-phone":"Phone","entity-details-email":"Email","add-to-metadata":"Add selected details to message metadata","add-to-metadata-hint":"If selected, adds the selected details keys to the message metadata instead of message data.","entity-details-list-empty":"No entity details selected.","no-entity-details-matching":"No entity details matching were found.","custom-table-name":"Custom table name","custom-table-name-required":"Table Name is required","custom-table-hint":"You should enter the table name without prefix 'cs_tb_'.","message-field":"Message field","message-field-required":"Message field is required.","table-col":"Table column","table-col-required":"Table column is required.","latitude-key-name":"Latitude key name","longitude-key-name":"Longitude key name","latitude-key-name-required":"Latitude key name is required.","longitude-key-name-required":"Longitude key name is required.","fetch-perimeter-info-from-message-metadata":"Fetch perimeter information from message metadata","perimeter-circle":"Circle","perimeter-polygon":"Polygon","perimeter-type":"Perimeter type","circle-center-latitude":"Center latitude","circle-center-latitude-required":"Center latitude is required.","circle-center-longitude":"Center longitude","circle-center-longitude-required":"Center longitude is required.","range-unit-meter":"Meter","range-unit-kilometer":"Kilometer","range-unit-foot":"Foot","range-unit-mile":"Mile","range-unit-nautical-mile":"Nautical mile","range-units":"Range units",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].","min-inside-duration":"Minimal inside duration","min-inside-duration-value-required":"Minimal inside duration is required","min-inside-duration-time-unit":"Minimal inside duration time unit","min-outside-duration":"Minimal outside duration","min-outside-duration-value-required":"Minimal outside duration is required","min-outside-duration-time-unit":"Minimal outside duration time unit","tell-failure-if-absent":"Tell Failure","tell-failure-if-absent-hint":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"get-latest-value-with-ts":"Fetch Latest telemetry with Timestamp","get-latest-value-with-ts-hint":'If selected, latest telemetry values will be added to the outbound message metadata with timestamp, e.g: "temp": "{\\"ts\\":1574329385897,\\"value\\":42}"',"use-redis-queue":"Use redis queue for message persistence","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules"},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"}}},!0)}(e)}return e.ctorParameters=function(){return[{type:n.TranslateService}]},e=b([t.NgModule({declarations:[F],imports:[r.CommonModule,a.SharedModule],exports:[xe,Ae,Be,He,F]}),h("design:paramtypes",[n.TranslateService])],e)}();e.RuleNodeCoreConfigModule=ze,e.ɵa=F,e.ɵb=xe,e.ɵba=he,e.ɵbb=Ce,e.ɵbc=ve,e.ɵbd=Fe,e.ɵbe=se,e.ɵbf=ne,e.ɵbg=ae,e.ɵbh=oe,e.ɵbi=ie,e.ɵbj=le,e.ɵbk=Ae,e.ɵbl=Te,e.ɵbm=qe,e.ɵbn=Se,e.ɵbo=Ie,e.ɵbp=ke,e.ɵbq=Ne,e.ɵbr=Ve,e.ɵbs=Ee,e.ɵbt=Be,e.ɵbu=Le,e.ɵbv=Me,e.ɵbw=Pe,e.ɵbx=Re,e.ɵby=we,e.ɵbz=Oe,e.ɵc=x,e.ɵca=De,e.ɵcb=Ke,e.ɵcc=He,e.ɵcd=Ge,e.ɵce=Ue,e.ɵcf=je,e.ɵd=T,e.ɵe=q,e.ɵf=S,e.ɵg=I,e.ɵh=k,e.ɵi=N,e.ɵj=V,e.ɵk=E,e.ɵl=A,e.ɵm=L,e.ɵn=X,e.ɵo=ee,e.ɵp=te,e.ɵq=re,e.ɵr=me,e.ɵs=ue,e.ɵt=de,e.ɵu=pe,e.ɵv=ce,e.ɵw=fe,e.ɵx=ge,e.ɵy=ye,e.ɵz=be,Object.defineProperty(e,"__esModule",{value:!0})})); //# sourceMappingURL=rulenode-core-config.umd.min.js.map \ No newline at end of file From 3b65e3c23c0dc2a3192fa0c2cee3121fa5c79166 Mon Sep 17 00:00:00 2001 From: zbeacon Date: Mon, 18 Jan 2021 13:50:00 +0200 Subject: [PATCH 038/249] Refactoring --- .../server/transport/mqtt/session/GatewayDeviceSessionCtx.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java index 1983c3f68d..db9ea66c44 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java @@ -41,7 +41,7 @@ public class GatewayDeviceSessionCtx extends MqttDeviceAwareSessionContext imple this.parent = parent; JsonParser parser = new JsonParser(); boolean activityTimeFromGatewayDevice = Boolean.FALSE; - if ("null".equals(this.parent.getDeviceInfo().getAdditionalInfo())) { + if (this.parent.getDeviceInfo().getAdditionalInfo() != null && !"null".equals(this.parent.getDeviceInfo().getAdditionalInfo())) { JsonObject additionalInfo = parser.parse(this.parent.getDeviceInfo().getAdditionalInfo()).getAsJsonObject(); if (additionalInfo.get("activityTimeFromGatewayDevice") != null) { activityTimeFromGatewayDevice = additionalInfo.get("activityTimeFromGatewayDevice").getAsBoolean(); From dac700d4febbe88c8355f9afc029c8b6cff38f1a Mon Sep 17 00:00:00 2001 From: Chantsova Ekaterina Date: Mon, 18 Jan 2021 14:06:35 +0200 Subject: [PATCH 039/249] Add ImportExport service to Services Map --- ui-ngx/src/app/modules/home/models/services.map.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/models/services.map.ts b/ui-ngx/src/app/modules/home/models/services.map.ts index 9e33301ed7..64e94f24df 100644 --- a/ui-ngx/src/app/modules/home/models/services.map.ts +++ b/ui-ngx/src/app/modules/home/models/services.map.ts @@ -32,7 +32,8 @@ import { DashboardService } from '@core/http/dashboard.service'; import { UserService } from '@core/http/user.service'; import { AlarmService } from '@core/http/alarm.service'; import { Router } from '@angular/router'; -import { BroadcastService } from "@core/services/broadcast.service"; +import { BroadcastService } from '@core/services/broadcast.service'; +import { ImportExportService } from '@home/components/import-export/import-export.service'; export const ServicesMap = new Map>( [ @@ -53,6 +54,7 @@ export const ServicesMap = new Map>( ['utils', UtilsService], ['translate', TranslateService], ['http', HttpClient], - ['router', Router] + ['router', Router], + ['importExport', ImportExportService] ] ); From 85bfbce2a43048a407de0dc6d006e22f79c8a3e5 Mon Sep 17 00:00:00 2001 From: Viacheslav Kukhtyn Date: Mon, 18 Jan 2021 18:13:32 +0200 Subject: [PATCH 040/249] Fix for basic credentials --- .../java/org/thingsboard/rule/engine/rest/TbHttpClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java index 102d772056..a4dd32a18e 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java @@ -281,7 +281,7 @@ public class TbHttpClient { private void addAuthorizationHeader(HttpHeaders headers) { HttpClientCredentials credentials = config.getCredentials(); if (CredentialsType.BASIC == credentials.getType()) { - headers.add("Authorization", ((HttpBasicCredentials) credentials).getPassword()); + headers.add("Authorization", ((HttpBasicCredentials) credentials).getBasicAuthHeaderValue()); } } } From cfa9a5778a9ae7b26c92dc80cb7e4d9265a8a11f Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 19 Jan 2021 16:24:58 +0200 Subject: [PATCH 041/249] Lwm2m: front: refactoring --- .../lwm2m-device-config-server.component.html | 27 ++- .../lwm2m-device-config-server.component.ts | 76 +++--- ...ile-transport-configuration.component.html | 218 +++++++++--------- ...ofile-transport-configuration.component.ts | 132 ++++++----- ...m2m-object-add-instances-list.component.ts | 68 +++--- .../lwm2m-object-add-instances.component.html | 2 +- .../lwm2m-object-add-instances.component.ts | 6 +- .../lwm2m/lwm2m-object-list.component.ts | 82 +++---- ...serve-attr-telemetry-resource.component.ts | 41 ++-- .../lwm2m-observe-attr-telemetry.component.ts | 153 ++++++------ .../device/lwm2m/profile-config.models.ts | 108 ++++----- .../home/pages/device/device.module.ts | 3 +- .../security-config-server.component.html | 57 +++-- .../lwm2m/security-config-server.component.ts | 62 +++-- .../lwm2m/security-config.component.html | 206 +++++++++-------- .../device/lwm2m/security-config.component.ts | 185 +++++++-------- .../device/lwm2m/security-config.models.ts | 54 +++-- .../components/json-object-edit.component.ts | 6 +- .../assets/locale/locale.constant-en_US.json | 10 +- 19 files changed, 778 insertions(+), 718 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html index 5f8c1080bc..f0fe7d8dcd 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html @@ -90,9 +90,14 @@ serverFormGroup.get('securityMode').value === securityConfigLwM2MType.X509"> {{ 'device-profile.lwm2m.server-public-key' | translate }} - {{serverPublicKey.value?.length || 0}}/{{lenMaxServerPublicKey}} @@ -101,14 +106,18 @@ {{ 'device-profile.lwm2m.required' | translate }} - {{ 'device-profile.lwm2m.client-key' | translate }} - {{ 'device-profile.lwm2m.pattern_hex_dec_182' | translate }} + (serverFormGroup.get('securityMode').value === securityConfigLwM2MType.RPK || + serverFormGroup.get('securityMode').value === securityConfigLwM2MType.X509)"> + {{ 'device-profile.lwm2m.server-public-key' | translate }} + {{ translate.get('device-profile.lwm2m.pattern_hex_dec', { + count: 0}) | async }} - - {{ 'device-profile.lwm2m.client-key' | translate }} - {{ 'device-profile.lwm2m.pattern_hex_dec' | translate }} + + {{ 'device-profile.lwm2m.server-public-key' | translate }} + {{ translate.get('device-profile.lwm2m.pattern_hex_dec', { + count: lenMaxServerPublicKey }) | async }}
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts index 01352af36e..e02a4e7c3a 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts @@ -14,31 +14,28 @@ /// limitations under the License. /// -import { Component, forwardRef, Inject, Input, OnInit } from "@angular/core"; +import { Component, forwardRef, Inject, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, - FormBuilder, FormGroup, NG_VALUE_ACCESSOR, NgModel, Validators -} from "@angular/forms"; + FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators +} from '@angular/forms'; import { SECURITY_CONFIG_MODE, SECURITY_CONFIG_MODE_NAMES, - KEY_PUBLIC_REGEXP_PSK, ServerSecurityConfig, - LEN_MAX_PUBLIC_KEY_PSK, - LEN_MAX_PUBLIC_KEY_RPK_X509, - KEY_PUBLIC_REGEXP_X509, DEFAULT_PORT_BOOTSTRAP_NO_SEC, DEFAULT_PORT_SERVER_NO_SEC, DEFAULT_CLIENT_HOLD_OFF_TIME, - DEFAULT_ID_SERVER -} from "./profile-config.models"; -import { Store } from "@ngrx/store"; -import { AppState } from "@core/core.state"; -import { coerceBooleanProperty } from "@angular/cdk/coercion"; -import { WINDOW } from "@core/services/window.service"; + DEFAULT_ID_SERVER, LEN_MAX_PUBLIC_KEY_RPK, LEN_MAX_PUBLIC_KEY_X509, KEY_REGEXP_HEX_DEC +} from './profile-config.models'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { coerceBooleanProperty } from '@angular/cdk/coercion'; +import { WINDOW } from '@core/services/window.service'; import { pairwise, startWith } from 'rxjs/operators'; import { DeviceProfileService } from '@core/http/device-profile.service'; +import { TranslateService } from '@ngx-translate/core'; @Component({ selector: 'tb-profile-lwm2m-device-config-server', @@ -55,12 +52,14 @@ import { DeviceProfileService } from '@core/http/device-profile.service'; export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAccessor, Validators { private requiredValue: boolean; + valuePrev = null; serverFormGroup: FormGroup; securityConfigLwM2MType = SECURITY_CONFIG_MODE; securityConfigLwM2MTypes = Object.keys(SECURITY_CONFIG_MODE); credentialTypeLwM2MNamesMap = SECURITY_CONFIG_MODE_NAMES; - lenMaxServerPublicKey = LEN_MAX_PUBLIC_KEY_PSK; + lenMinServerPublicKey = 0; + lenMaxServerPublicKey = LEN_MAX_PUBLIC_KEY_RPK; currentSecurityMode = null; @@ -80,6 +79,7 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc } constructor(protected store: Store, + public translate: TranslateService, public fb: FormBuilder, private deviceProfileService: DeviceProfileService, @Inject(WINDOW) private window: Window) { @@ -105,7 +105,7 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc ngOnInit(): void { } - updateValueFields(serverData: ServerSecurityConfig): void { + private updateValueFields = (serverData: ServerSecurityConfig): void => { serverData.bootstrapServerIs = this.bootstrapServerIs; this.serverFormGroup.patchValue(serverData, {emitEvent: false}); this.serverFormGroup.get('bootstrapServerIs').disable(); @@ -113,40 +113,38 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc this.updateValidate(securityMode); } - updateValidate(securityMode: SECURITY_CONFIG_MODE): void { + private updateValidate = (securityMode: SECURITY_CONFIG_MODE): void => { switch (securityMode) { case SECURITY_CONFIG_MODE.NO_SEC: - this.serverFormGroup.get('serverPublicKey').setValidators([]); + this.setValidatorsNoSecPsk(); break; case SECURITY_CONFIG_MODE.PSK: - this.lenMaxServerPublicKey = LEN_MAX_PUBLIC_KEY_PSK; - this.serverFormGroup.get('serverPublicKey').setValidators([]); + this.setValidatorsNoSecPsk(); break; case SECURITY_CONFIG_MODE.RPK: - this.lenMaxServerPublicKey = LEN_MAX_PUBLIC_KEY_RPK_X509; - this.serverFormGroup.get('serverPublicKey').setValidators([Validators.required, Validators.pattern(KEY_PUBLIC_REGEXP_PSK)]); + this.lenMinServerPublicKey = LEN_MAX_PUBLIC_KEY_RPK; + this.lenMaxServerPublicKey = LEN_MAX_PUBLIC_KEY_RPK; + this.setValidatorsRpkX509(); break; case SECURITY_CONFIG_MODE.X509: - this.lenMaxServerPublicKey = LEN_MAX_PUBLIC_KEY_RPK_X509; - this.serverFormGroup.get('serverPublicKey').setValidators([Validators.required, Validators.pattern(KEY_PUBLIC_REGEXP_X509)]); + this.lenMinServerPublicKey = 0; + this.lenMaxServerPublicKey = LEN_MAX_PUBLIC_KEY_X509; + this.setValidatorsRpkX509(); break; } this.serverFormGroup.updateValueAndValidity(); - // this.checkValueWithNewValidate(); } - // checkValueWithNewValidate(): void { - // this.serverFormGroup.patchValue({ - // host: this.serverFormGroup.get('host').value, - // port: this.serverFormGroup.get('port').value, - // bootstrapServerIs: this.serverFormGroup.get('bootstrapServerIs').value, - // serverPublicKey: this.serverFormGroup.get('serverPublicKey').value, - // clientHoldOffTime: this.serverFormGroup.get('clientHoldOffTime').value, - // serverId: this.serverFormGroup.get('serverId').value, - // bootstrapServerAccountTimeout: this.serverFormGroup.get('bootstrapServerAccountTimeout').value, - // }, - // {emitEvent: true}); - // } + private setValidatorsNoSecPsk = (): void => { + this.serverFormGroup.get('serverPublicKey').setValidators([]); + } + + private setValidatorsRpkX509 = (): void => { + this.serverFormGroup.get('serverPublicKey').setValidators([Validators.required, + Validators.pattern(KEY_REGEXP_HEX_DEC), + Validators.minLength(this.lenMinServerPublicKey), + Validators.maxLength(this.lenMaxServerPublicKey)]); + } writeValue(value: any): void { if (value) { @@ -160,7 +158,7 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc this.propagateChange = fn; } - private propagateChangeState(value: any): void { + private propagateChangeState = (value: any): void => { if (value !== undefined) { if (this.valuePrev === null) { this.valuePrev = 'init'; @@ -190,7 +188,7 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc registerOnTouched(fn: any): void { } - getServerGroup(): FormGroup { + private getServerGroup = (): FormGroup => { const port = this.bootstrapServerIs ? DEFAULT_PORT_BOOTSTRAP_NO_SEC : DEFAULT_PORT_SERVER_NO_SEC; return this.fb.group({ host: [this.window.location.hostname, this.required ? [Validators.required] : []], @@ -204,7 +202,7 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc }); } - getLwm2mBootstrapSecurityInfo(mode: string) { + private getLwm2mBootstrapSecurityInfo = (mode: string): void => { this.deviceProfileService.getLwm2mBootstrapSecurityInfo(mode, this.serverFormGroup.get('bootstrapServerIs').value).subscribe( (serverSecurityConfig) => { this.serverFormGroup.patchValue({ diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html index 5e9c5d27f4..3eadd43c53 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html @@ -19,118 +19,126 @@
-
- - -
-
- - -
+ +
+ + +
+
+ + +
+
-
- - - - -
{{ 'device-profile.lwm2m.servers' | translate | uppercase }}
-
-
-
-
- - {{ 'device-profile.lwm2m.short-id' | translate }} - - - {{ 'device-profile.lwm2m.short-id' | translate }} - {{ 'device-profile.lwm2m.required' | translate }} - - - - {{ 'device-profile.lwm2m.lifetime' | translate }} - - - {{ 'device-profile.lwm2m.lifetime' | translate }} - {{ 'device-profile.lwm2m.required' | translate }} - - + +
+ + + + +
{{ 'device-profile.lwm2m.servers' | translate | uppercase }}
+
+
+
+
+ + {{ 'device-profile.lwm2m.short-id' | translate }} + + + {{ 'device-profile.lwm2m.short-id' | translate }} + {{ 'device-profile.lwm2m.required' | translate }} + + + + {{ 'device-profile.lwm2m.lifetime' | translate }} + + + {{ 'device-profile.lwm2m.lifetime' | translate }} + {{ 'device-profile.lwm2m.required' | translate }} + + +
+
+ + {{ 'device-profile.lwm2m.default-min-period' | translate }} + + + {{ 'device-profile.lwm2m.default-min-period' | translate }} + {{ 'device-profile.lwm2m.required' | translate }} + + + + {{ 'device-profile.lwm2m.binding' | translate }} + + + {{ 'device-profile.lwm2m.binding' | translate }} + {{ 'device-profile.lwm2m.required' | translate }} + + +
+
+ + {{ 'device-profile.lwm2m.notif-if-disabled' | translate }} + +
-
- - {{ 'device-profile.lwm2m.default-min-period' | translate }} - - - {{ 'device-profile.lwm2m.default-min-period' | translate }} - {{ 'device-profile.lwm2m.required' | translate }} - - - - {{ 'device-profile.lwm2m.binding' | translate }} - - - {{ 'device-profile.lwm2m.binding' | translate }} - {{ 'device-profile.lwm2m.required' | translate }} - - + + + + + + +
{{ 'device-profile.lwm2m.bootstrap-server' | translate | uppercase }}
+
+
+
+ +
-
- - {{ 'device-profile.lwm2m.notif-if-disabled' | translate }} - + + + + + + +
{{ 'device-profile.lwm2m.lwm2m-server' | translate | uppercase }}
+
+
+
+ +
-
-
-
- - - - -
{{ 'device-profile.lwm2m.bootstrap-server' | translate | uppercase }}
-
-
-
- - -
-
-
- - - - -
{{ 'device-profile.lwm2m.lwm2m-server' | translate | uppercase }}
-
-
-
- - -
-
-
-
+
+
+
+
-
- - -
+ +
+ + +
+
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts index 9071fc4a2b..b1f87568ad 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts @@ -34,10 +34,10 @@ import { OBSERVE_ATTR, TELEMETRY, ObjectLwM2M, getDefaultProfileConfig, KEY_NAME, Instance, ProfileConfigModels, ResourceLwM2M -} from "./profile-config.models"; -import { DeviceProfileService } from "@core/http/device-profile.service"; -import { deepClone, isUndefined } from "@core/utils"; -import { WINDOW } from "@core/services/window.service"; +} from './profile-config.models'; +import { DeviceProfileService } from '@core/http/device-profile.service'; +import { deepClone, isUndefined } from '@core/utils'; +import { WINDOW } from '@core/services/window.service'; import { JsonObject } from '@angular/compiler-cli/ngcc/src/packages/entry_point'; import { isNotNullOrUndefined } from 'codelyzer/util/isNotNullOrUndefined'; @@ -65,7 +65,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro bootstrapServers: string; bootstrapServer: string; lwm2mServer: string; - sortFunction = this.sortObjectKeyPathJson; + sortFunction: {}; get required(): boolean { return this.requiredValue; @@ -76,7 +76,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro this.requiredValue = coerceBooleanProperty(value); } - private propagateChange = (v: any) => { }; + private propagateChange = (v: any) => { }; constructor(private store: Store, private fb: FormBuilder, @@ -109,6 +109,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } ngOnInit() { + this.sortFunction = this.sortObjectKeyPathJson; } setDisabledState(isDisabled: boolean): void { @@ -130,22 +131,22 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro this.initWriteValue(); } - private initWriteValue(): void { + private initWriteValue = (): void => { const modelValue = {objectIds: null, objectsList: []}; modelValue.objectIds = this.getObjectsFromJsonAllConfig(); if (modelValue.objectIds !== null) { this.deviceProfileService.getLwm2mObjects(modelValue.objectIds).subscribe( - (objectsList) => { - modelValue.objectsList = objectsList; - this.updateWriteValue(modelValue); - } + (objectsList) => { + modelValue.objectsList = objectsList; + this.updateWriteValue(modelValue); + } ); } else { this.updateWriteValue(modelValue); } } - private updateWriteValue(value: any): void { + private updateWriteValue = (value: any): void => { const objectsList = deepClone(value.objectsList); this.lwm2mDeviceProfileTransportConfFormGroup.patchValue({ objectIds: value, @@ -161,7 +162,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro {emitEvent: false}); } - private updateModel() { + private updateModel = (): void => { let configuration: DeviceProfileTransportConfiguration = null; if (this.lwm2mDeviceProfileTransportConfFormGroup.valid) { this.upDateValueToJson(); @@ -171,25 +172,25 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro this.propagateChange(configuration); } - private updateObserveAttrTelemetryObjectFormGroup(objectsList: ObjectLwM2M[]) { + private updateObserveAttrTelemetryObjectFormGroup = (objectsList: ObjectLwM2M[]): void => { this.lwm2mDeviceProfileTransportConfFormGroup.patchValue({ - observeAttrTelemetry: {clientLwM2M: this.getObserveAttrTelemetryObjects(objectsList)} - }, - {emitEvent: false}); + observeAttrTelemetry: {clientLwM2M: this.getObserveAttrTelemetryObjects(objectsList)} + }, + {emitEvent: false}); this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').markAsPristine({ onlySelf: true }); } - upDateValueToJson(): void { - this.upDateValueToJsonTab_0(); - this.upDateValueToJsonTab_1(); + private upDateValueToJson = (): void => { + this.upDateValueToJsonTab0(); + this.upDateValueToJsonTab1(); } - upDateValueToJsonTab_0(): void { + private upDateValueToJsonTab0 = (): void => { if (!this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').pristine) { this.upDateObserveAttrTelemetryFromGroupToJson( - this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').value.clientLwM2M + this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').value.clientLwM2M ); this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').markAsPristine({ onlySelf: true @@ -198,7 +199,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } } - upDateValueToJsonTab_1(): void { + private upDateValueToJsonTab1 = (): void => { this.upDateValueServersToJson(); if (!this.lwm2mDeviceProfileTransportConfFormGroup.get('bootstrapServer').pristine) { this.configurationValue.bootstrap.bootstrapServer = this.lwm2mDeviceProfileTransportConfFormGroup.get('bootstrapServer').value; @@ -216,7 +217,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } } - upDateValueServersToJson(): void { + private upDateValueServersToJson = (): void => { const bootstrapServers = this.configurationValue.bootstrap.servers; if (!this.lwm2mDeviceProfileTransportConfFormGroup.get('shortId').pristine) { bootstrapServers.shortId = this.lwm2mDeviceProfileTransportConfFormGroup.get('shortId').value; @@ -255,7 +256,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } } - getObserveAttrTelemetryObjects(listObject: ObjectLwM2M[]): ObjectLwM2M [] { + private getObserveAttrTelemetryObjects = (listObject: ObjectLwM2M[]): ObjectLwM2M [] => { const clientObserveAttr = deepClone(listObject); if (this.configurationValue[this.observeAttr]) { const observeArray = this.configurationValue[this.observeAttr][this.observe] as Array; @@ -284,12 +285,13 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro return clientObserveAttr; } - includesInstancesNo(attributeArray: Array, telemetryArray: Array): boolean { + private includesInstancesNo = (attributeArray: Array, telemetryArray: Array): boolean => { const isIdIndex = (element) => !element.includes('/0/'); return attributeArray.findIndex(isIdIndex) >= 0 || telemetryArray.findIndex(isIdIndex) >= 0; } - addInstances(attributeArray: Array, telemetryArray: Array, clientObserveAttr: ObjectLwM2M[]): void { + private addInstances = (attributeArray: Array, telemetryArray: Array, + clientObserveAttr: ObjectLwM2M[]): void => { const attr = [] as Array; [...attributeArray].filter(x => (!x.includes('/0/'))).forEach(x => { attr.push(this.convertPathToInstance(x)); @@ -310,42 +312,43 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro }); } - convertPathToInstance(path: string): string { + private convertPathToInstance = (path: string): string => { const newX = Array.from(path.substring(1).split('/'), Number); return [newX[0], newX[1]].join('/'); } - updateObserveAttrTelemetryObjects(isParameter: Array, clientObserveAttr: ObjectLwM2M[], nameParameter: string): void { + private updateObserveAttrTelemetryObjects = (isParameter: Array, clientObserveAttr: ObjectLwM2M[], + nameParameter: string): void => { isParameter.forEach(attr => { const idKeys = Array.from(attr.substring(1).split('/'), Number); clientObserveAttr - .forEach(e => { - if (e.id === idKeys[0]) { - const instance = e.instances.find(itrInstance => itrInstance.id === idKeys[1]); - if (isNotNullOrUndefined(instance)) { - instance.resources.find(resource => resource.id === idKeys[2])[nameParameter] = true; - } + .forEach(e => { + if (e.id === idKeys[0]) { + const instance = e.instances.find(itrInstance => itrInstance.id === idKeys[1]); + if (isNotNullOrUndefined(instance)) { + instance.resources.find(resource => resource.id === idKeys[2])[nameParameter] = true; } - }); + } + }); }); } - updateKeyNameObjects(nameJson: JsonObject, clientObserveAttr: ObjectLwM2M[]): void { + private updateKeyNameObjects = (nameJson: JsonObject, clientObserveAttr: ObjectLwM2M[]): void => { const keyName = JSON.parse(JSON.stringify(nameJson)); Object.keys(keyName).forEach(key => { const idKeys = Array.from(key.substring(1).split('/'), Number); clientObserveAttr - .forEach(e => { - if (e.id === idKeys[0]) { - e.instances - .find(instance => instance.id === idKeys[1]).resources - .find(resource => resource.id === idKeys[2]).keyName = keyName[key]; - } - }); + .forEach(e => { + if (e.id === idKeys[0]) { + e.instances + .find(instance => instance.id === idKeys[1]).resources + .find(resource => resource.id === idKeys[2]).keyName = keyName[key]; + } + }); }); } - upDateObserveAttrTelemetryFromGroupToJson(val: ObjectLwM2M[]): void { + private upDateObserveAttrTelemetryFromGroupToJson = (val: ObjectLwM2M[]): void => { const observeArray: Array = []; const attributeArray: Array = []; const telemetryArray: Array = []; @@ -405,19 +408,22 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro this.updateKeyName(); } - sortObjectKeyPathJson(key, value) { + sortObjectKeyPathJson = (key: string, value: object): object => { if (key === 'keyName') { return Object.keys(value).sort((a, b) => { const aLC = Array.from(a.substring(1).split('/'), Number); const bLC = Array.from(b.substring(1).split('/'), Number); return aLC[0] === bLC[0] ? aLC[1] - bLC[1] : aLC[0] - bLC[0]; - }).reduce((r, k) => r[k] = value[k], {}); + }).reduce((obj, keySort) => { + obj[keySort] = value[keySort]; + return obj; + }, {}); } else { return value; } } - updateKeyName(): void { + private updateKeyName = (): void => { const paths = new Set(); if (this.configurationValue[this.observeAttr][this.attribute]) { this.configurationValue[this.observeAttr][this.attribute].forEach(path => { @@ -431,20 +437,20 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } const keyNameNew = {}; paths.forEach(path => { - const pathParameter = this.findIndexsForIds(path); + const pathParameter = this.findIndexesForIds(path); if (pathParameter.length === 3) { keyNameNew[path] = this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').value - .clientLwM2M[pathParameter[0]].instances[pathParameter[1]].resources[pathParameter[2]][this.keyName]; + .clientLwM2M[pathParameter[0]].instances[pathParameter[1]].resources[pathParameter[2]][this.keyName]; } }); this.configurationValue[this.observeAttr][this.keyName] = this.sortObjectKeyPathJson('keyName', keyNameNew); } - findIndexsForIds(path: string): number[] { + private findIndexesForIds = (path: string): number[] => { const pathParameter = Array.from(path.substring(1).split('/'), Number); const pathParameterIndexes: number[] = []; const objectsOld = deepClone( - this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').value.clientLwM2M) as ObjectLwM2M[]; + this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').value.clientLwM2M) as ObjectLwM2M[]; let isIdIndex = (element) => element.id === pathParameter[0]; const objIndex = objectsOld.findIndex(isIdIndex); if (objIndex >= 0) { @@ -463,7 +469,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro return pathParameterIndexes; } - getObjectsFromJsonAllConfig(): number [] { + private getObjectsFromJsonAllConfig = (): number [] => { const objectsIds = new Set(); if (this.configurationValue[this.observeAttr]) { if (this.configurationValue[this.observeAttr][this.observe]) { @@ -485,7 +491,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro return (objectsIds.size > 0) ? Array.from(objectsIds) : null; } - upDateJsonAllConfig(): void { + private upDateJsonAllConfig = (): void => { this.lwm2mDeviceProfileTransportConfFormGroup.patchValue({ configurationJson: this.configurationValue }, {emitEvent: false}); @@ -494,11 +500,11 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro }); } - addObjectsList(value: ObjectLwM2M[]): void { + addObjectsList = (value: ObjectLwM2M[]): void => { this.updateObserveAttrTelemetryObjectFormGroup(deepClone(value)); } - removeObjectsList(value: ObjectLwM2M): void { + removeObjectsList = (value: ObjectLwM2M): void => { const objectsOld = deepClone(this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').value.clientLwM2M); const isIdIndex = (element) => element.id === value.id; const index = objectsOld.findIndex(isIdIndex); @@ -514,7 +520,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro this.upDateJsonAllConfig(); } - removeObserveAttrTelemetryFromJson(observeAttrTel: string, id: number): void { + private removeObserveAttrTelemetryFromJson = (observeAttrTel: string, id: number): void => { const isIdIndex = (element) => Array.from(element.substring(1).split('/'), Number)[0] === id; let index = this.configurationValue[this.observeAttr][observeAttrTel].findIndex(isIdIndex); while (index >= 0) { @@ -523,12 +529,12 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } } - removeKeyNameFromJson(id: number): void { - const keyNmaeJson = this.configurationValue[this.observeAttr][this.keyName]; - Object.keys(keyNmaeJson).forEach(key => { + private removeKeyNameFromJson = (id: number): void => { + const keyNameJson = this.configurationValue[this.observeAttr][this.keyName]; + Object.keys(keyNameJson).forEach(key => { const idKey = Array.from(key.substring(1).split('/'), Number)[0]; if (idKey === id) { - delete keyNmaeJson[key]; + delete keyNameJson[key]; } }); } @@ -538,10 +544,10 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro if (!isPath) { isPath = this.findPathInJson(path, this.telemetry); } - return (isPath) ? true : false; + return !!isPath; } - findPathInJson(path: string, side: string): string { + private findPathInJson = (path: string, side: string): string => { if (this.configurationValue[this.observeAttr]) { if (this.configurationValue[this.observeAttr][side]) { return this.configurationValue[this.observeAttr][side].find( diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.ts index 44d9066440..acbebca313 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.ts @@ -21,44 +21,45 @@ import { OnInit, ViewChild, ElementRef, -} from "@angular/core"; +} from '@angular/core'; import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators -} from "@angular/forms"; -import { coerceBooleanProperty } from "@angular/cdk/coercion"; -import { Store } from "@ngrx/store"; -import { AppState } from "@core/core.state"; +} from '@angular/forms'; +import { coerceBooleanProperty } from '@angular/cdk/coercion'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; import { MatChipList } from '@angular/material/chips'; import { INSTANCES_ID_VALUE_MAX, INSTANCES_ID_VALUE_MIN -} from "./profile-config.models"; -import { TranslateService } from "@ngx-translate/core"; -import { DeviceProfileService } from "@core/http/device-profile.service"; +} from './profile-config.models'; +import { TranslateService } from '@ngx-translate/core'; +import { DeviceProfileService } from '@core/http/device-profile.service'; @Component({ selector: 'tb-profile-lwm2m-object-add-instances-list', templateUrl: './lwm2m-object-add-instances-list.component.html', styleUrls: ['./lwm2m-object-add-instances-list.component.scss'], providers: [{ - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => Lwm2mObjectAddInstancesListComponent), - multi: true - }] + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => Lwm2mObjectAddInstancesListComponent), + multi: true + }] }) export class Lwm2mObjectAddInstancesListComponent implements ControlValueAccessor, OnInit, Validators { - lwm2mObjectListFormGroup: FormGroup; private requiredValue: boolean; - private instancesIdsList: Set | null; - filteredObjectsList: Array; private disabled = false as boolean; private dirty = false as boolean; - instanceIdValueMin = INSTANCES_ID_VALUE_MIN as number - instanceIdValueMax = INSTANCES_ID_VALUE_MAX as number + + lwm2mObjectListFormGroup: FormGroup; + instancesIdsList: Set | null; + filteredObjectsList: Array; + instanceIdValueMin = INSTANCES_ID_VALUE_MIN as number; + instanceIdValueMax = INSTANCES_ID_VALUE_MAX as number; get required(): boolean { return this.requiredValue; @@ -76,8 +77,7 @@ export class Lwm2mObjectAddInstancesListComponent implements ControlValueAccesso @ViewChild('instanceIdInput') instanceIdInput: ElementRef; @ViewChild('chipList', {static: true}) chipList: MatChipList; - private propagateChange = (v: any) => { - }; + private propagateChange = (v: any) => { }; constructor(private store: Store, public translate: TranslateService, @@ -89,7 +89,7 @@ export class Lwm2mObjectAddInstancesListComponent implements ControlValueAccesso }); } - updateValidators() { + private updateValidators = (): void => { this.lwm2mObjectListFormGroup.get('instanceIdInput').setValidators([ Validators.min(this.instanceIdValueMin), Validators.max(this.instanceIdValueMax)]); @@ -128,41 +128,41 @@ export class Lwm2mObjectAddInstancesListComponent implements ControlValueAccesso this.dirty = false; } - add(value: number): void { + add = (value: number): void => { if (!isNaN(value) && this.lwm2mObjectListFormGroup.get('instanceIdInput').valid) { this.instancesIdsList.add(value); this.lwm2mObjectListFormGroup.get('instancesIdsList').setValue(this.instancesIdsList); this.propagateChange(this.instancesIdsList); - this.dirty = true + this.dirty = true; } this.clear(); } - remove(object: number) { + remove = (object: number): void => { this.instancesIdsList.delete(object); this.lwm2mObjectListFormGroup.get('instancesIdsList').setValue(this.instancesIdsList); this.propagateChange(this.instancesIdsList); - this.dirty = true + this.dirty = true; this.clear(); } + // + // displayFn(object?: number): number | undefined { + // return object ? object : undefined; + // } - displayFn(object?: number): number | undefined { - return object ? object : undefined; - } - - clear() { + private clear = (): void => { this.lwm2mObjectListFormGroup.get('instanceIdInput').patchValue(null, {emitEvent: true}); - this.instanceIdInput.nativeElement.value = ""; + this.instanceIdInput.nativeElement.value = ''; setTimeout(() => { this.instanceIdInput.nativeElement.blur(); this.instanceIdInput.nativeElement.focus(); }, 0); } - onkeydown(e: KeyboardEvent) { - if (e.keyCode == 189 || e.keyCode == 187 || e.keyCode == 109 || e.keyCode == 107) { + onkeydown = (e: KeyboardEvent): boolean => { + if (e.keyCode === 189 || e.keyCode === 187 || e.keyCode === 109 || e.keyCode === 107) { return false; - } else if (e.keyCode == 8) { + } else if (e.keyCode === 8) { if (this.lwm2mObjectListFormGroup.get('instanceIdInput').value == null) { this.clear(); } @@ -170,7 +170,7 @@ export class Lwm2mObjectAddInstancesListComponent implements ControlValueAccesso } } - onFocus() { + onFocus = (): void => { if (this.dirty) { this.lwm2mObjectListFormGroup.get('instanceIdInput').updateValueAndValidity({onlySelf: true, emitEvent: true}); this.dirty = false; diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.html index b8d10689e1..6dafeb6024 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.html @@ -42,7 +42,7 @@ -
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.ts index 64beea1bdb..57c7e3e2b5 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.ts @@ -35,7 +35,7 @@ export interface Lwm2mObjectAddInstancesData { }) export class Lwm2mObjectAddInstancesComponent extends DialogComponent implements OnInit { - jsonFormGroup: FormGroup; + instancesFormGroup: FormGroup; submitted = false; constructor(protected store: Store, @@ -46,9 +46,8 @@ export class Lwm2mObjectAddInstancesComponent extends DialogComponent | null; objectsList: Array = []; filteredObjectsList: Observable>; - disabled = false as boolean; - searchText = '' as string; + disabled = false; + searchText = ''; get required(): boolean { return this.requiredValue; @@ -210,9 +196,7 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V direction: Direction.ASC }); return this.deviceProfileService.getLwm2mObjectsPage(pageLink, {ignoreLoading: true}).pipe( - map(pageData => { - return pageData.data; - }) + map(pageData => pageData.data) ); } diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resource.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resource.component.html index 322fba8086..c406cfb17f 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resource.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resource.component.html @@ -17,12 +17,10 @@ -->
-
-
-
- -
+ *ngFor="let resourceLwM2M of resourceFormArray.controls; let i = index; trackBy: trackByParams"> +
+
+
device-profile.lwm2m.observe-label @@ -72,10 +70,9 @@ {{ 'device-profile.lwm2m.key-name_label' | translate }} - {{ 'device-profile.lwm2m.key-name' | translate }} {{ 'device-profile.lwm2m.required' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resource.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resource.component.ts index 12eeaab029..8d3fa0c57b 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resource.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resource.component.ts @@ -14,20 +14,12 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; -import { - ControlValueAccessor, - FormArray, FormBuilder, - FormGroup, - NG_VALUE_ACCESSOR, Validators -} from '@angular/forms'; -import { - CAMEL_CASE_REGEXP, - ResourceLwM2M -} from '@home/components/profile/device/lwm2m/profile-config.models'; +import { Component, forwardRef, Input } from '@angular/core'; +import { ControlValueAccessor, FormArray, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; +import { ResourceLwM2M } from '@home/components/profile/device/lwm2m/profile-config.models'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; -import { deepClone } from '@core/utils'; +import _ from 'lodash'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; @Component({ @@ -43,12 +35,12 @@ import { coerceBooleanProperty } from '@angular/cdk/coercion'; ] }) -export class Lwm2mObserveAttrTelemetryResourceComponent implements ControlValueAccessor, OnInit, Validators { +export class Lwm2mObserveAttrTelemetryResourceComponent implements ControlValueAccessor { private requiredValue: boolean; resourceFormGroup: FormGroup; - disabled = false as boolean; + disabled = false; get required(): boolean { return this.requiredValue; @@ -61,9 +53,12 @@ export class Lwm2mObserveAttrTelemetryResourceComponent implements ControlValueA this.requiredValue = newVal; } } + constructor(private store: Store, private fb: FormBuilder) { - this.resourceFormGroup = this.fb.group({resources: this.fb.array([])}); + this.resourceFormGroup = this.fb.group({ + resources: this.fb.array([]) + }); this.resourceFormGroup.valueChanges.subscribe(value => { if (!this.disabled) { this.propagateChangeState(value.resources); @@ -71,9 +66,6 @@ export class Lwm2mObserveAttrTelemetryResourceComponent implements ControlValueA }); } - ngOnInit(): void { - } - registerOnTouched(fn: any): void { } @@ -85,10 +77,6 @@ export class Lwm2mObserveAttrTelemetryResourceComponent implements ControlValueA return this.resourceFormGroup.get('resources') as FormArray; } - resourceLwm2mFormArray = (instance: FormGroup): FormArray => { - return instance.get('resources') as FormArray; - } - setDisabledState(isDisabled: boolean): void { this.disabled = isDisabled; if (isDisabled) { @@ -98,31 +86,16 @@ export class Lwm2mObserveAttrTelemetryResourceComponent implements ControlValueA } } - getDisabledState = (): boolean => { - return this.disabled; - } - - updateValueKeyName = (event: any, z: number): void => { - this.resourceFormArray.at(z).patchValue( {keyName: this.keysToCamel(deepClone(event.target.value))} ); - } - - private keysToCamel = (o: any): string => { - const val = o.split(' '); - const playStore = []; - val.forEach((item, k) => { - item = item.replace(CAMEL_CASE_REGEXP, ''); - item = (k === 0) ? item.charAt(0).toLowerCase() + item.substr(1) : item.charAt(0).toUpperCase() + item.substr(1); - playStore.push(item); - }); - return playStore.join(''); + updateValueKeyName = (event: Event, index: number): void => { + this.resourceFormArray.at(index).patchValue({keyName: _.camelCase((event.target as HTMLInputElement).value)}); } - private createResourceLwM2M = (resourcesLwM2MJson: ResourceLwM2M []): void => { - if (resourcesLwM2MJson.length === this.resourceFormArray.length) { - this.resourceFormArray.patchValue(resourcesLwM2MJson, {emitEvent: false}); + createResourceLwM2M(resourcesLwM2M: ResourceLwM2M[]): void { + if (resourcesLwM2M.length === this.resourceFormArray.length) { + this.resourceFormArray.patchValue(resourcesLwM2M, {emitEvent: false}); } else { this.resourceFormArray.clear(); - resourcesLwM2MJson.forEach(resourceLwM2M => { + resourcesLwM2M.forEach(resourceLwM2M => { this.resourceFormArray.push(this.fb.group({ id: resourceLwM2M.id, name: resourceLwM2M.name, diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.html index ea3233f769..eb0e4bc88d 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.html @@ -19,7 +19,7 @@
@@ -34,8 +34,8 @@ -
- + +
-
- - -
+
+
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts index faed152a1b..11ffdf0fe5 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts @@ -15,7 +15,7 @@ /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, forwardRef, Input } from '@angular/core'; import { AbstractControl, ControlValueAccessor, @@ -28,16 +28,8 @@ import { import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; -import { - ATTR, - Instance, - ObjectLwM2M, - OBSERVE, - ResourceLwM2M, - TELEMETRY -} from './profile-config.models'; -import { isNotNullOrUndefined } from 'codelyzer/util/isNotNullOrUndefined'; -import { deepClone, isUndefined } from '@core/utils'; +import { Instance, ObjectLwM2M, ResourceLwM2M } from './profile-config.models'; +import { deepClone, isDefinedAndNotNull, isEqual, isUndefined } from '@core/utils'; import { MatDialog } from '@angular/material/dialog'; import { TranslateService } from '@ngx-translate/core'; import { @@ -58,24 +50,17 @@ import { ] }) -export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor, OnInit, Validators { +export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor { private requiredValue: boolean; valuePrev = null as any; observeAttrTelemetryFormGroup: FormGroup; - observe = OBSERVE as string; - attribute = ATTR as string; - telemetry = TELEMETRY as string; get required(): boolean { return this.requiredValue; } - @Input() - disabled: boolean; - - // tslint:disable-next-line:adjacent-overload-signatures @Input() set required(value: boolean) { const newVal = coerceBooleanProperty(value); @@ -85,6 +70,9 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor, } } + @Input() + disabled: boolean; + constructor(private store: Store, private fb: FormBuilder, private dialog: MatDialog, @@ -99,9 +87,6 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor, }); } - ngOnInit(): void { - } - private propagateChange = (v: any) => { }; @@ -139,10 +124,6 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor, } } - getDisabledState = (): boolean => { - return this.disabled; - } - writeValue(value: any): void { this.buildClientObjectsLwM2M(value.clientLwM2M); } @@ -153,8 +134,8 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor, ); } - private createObjectsLwM2M = (objectsLwM2MJson: ObjectLwM2M []): FormArray => { - return this.fb.array(objectsLwM2MJson.map((objectLwM2M) => { + private createObjectsLwM2M = (objectsLwM2M: ObjectLwM2M[]): FormArray => { + return this.fb.array(objectsLwM2M.map((objectLwM2M) => { return this.fb.group({ id: objectLwM2M.id, name: objectLwM2M.name, @@ -165,20 +146,17 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor, })); } - private createInstanceLwM2M = (instanceLwM2MJson: Instance []): FormArray => { - return this.fb.array(instanceLwM2MJson.map((instanceLwM2M) => { + private createInstanceLwM2M = (instancesLwM2M: Instance[]): FormArray => { + return this.fb.array(instancesLwM2M.map((instanceLwM2M) => { return this.fb.group({ id: instanceLwM2M.id, - [this.observe]: {value: false, disabled: this.disabled}, - [this.attribute]: {value: false, disabled: this.disabled}, - [this.telemetry]: {value: false, disabled: this.disabled}, resources: {value: instanceLwM2M.resources, disabled: this.disabled} }); })); } - clientLwM2MFormArray = (formGroup: FormGroup): FormArray => { - return formGroup.get('clientLwM2M') as FormArray; + get clientLwM2MFormArray(): FormArray { + return this.observeAttrTelemetryFormGroup.get('clientLwM2M') as FormArray; } instancesLwm2mFormArray = (objectLwM2M: AbstractControl): FormArray => { @@ -186,7 +164,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor, } changeInstanceResourcesCheckBox = (value: boolean, instance: AbstractControl, type: string): void => { - const resources = instance.get('resources').value as ResourceLwM2M []; + const resources = instance.get('resources').value as ResourceLwM2M[]; resources.forEach(resource => resource[type] = value); instance.get('resources').patchValue(resources); this.propagateChange(this.observeAttrTelemetryFormGroup.value); @@ -202,26 +180,18 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor, } getIndeterminate = (instance: AbstractControl, type: string): boolean => { - const resources = instance.get('resources').value as ResourceLwM2M []; - if (isNotNullOrUndefined(resources)) { - const isType = (element) => element[type] === true; - const checkedResource = resources.filter(isType); - if (checkedResource.length === 0) { return false; } - else if (checkedResource.length === resources.length) { - instance.patchValue({[type]: true}); - return false; - } else { return true; } + const resources = instance.get('resources').value as ResourceLwM2M[]; + if (isDefinedAndNotNull(resources)) { + const checkedResource = resources.filter(resource => resource[type]); + return checkedResource.length !== 0 && checkedResource.length !== resources.length; } return false; } getChecked = (instance: AbstractControl, type: string): boolean => { - const resources = instance.get('resources').value as ResourceLwM2M []; - if (isNotNullOrUndefined(resources)) { - return resources.some(resource => resource[type]); - } - return false; + const resources = instance.get('resources').value as ResourceLwM2M[]; + return isDefinedAndNotNull(resources) && resources.every(resource => resource[type]); } getExpended = (objectLwM2M: AbstractControl): boolean => { @@ -265,7 +235,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor, } }).afterClosed().subscribe( (res: Lwm2mObjectAddInstancesData | undefined) => { - if (isNotNullOrUndefined(res)) { + if (isDefinedAndNotNull(res)) { this.updateInstancesIds(res); } } @@ -278,43 +248,41 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor, data.instancesIds.forEach(value => { valueNew.add(value); }); - const oldInstances = (this.observeAttrTelemetryFormGroup.get('clientLwM2M').value as ObjectLwM2M []). - find(e => e.id === data.objectId).instances; + const oldInstances = (this.observeAttrTelemetryFormGroup.get('clientLwM2M').value as ObjectLwM2M []) + .find(e => e.id === data.objectId).instances; oldInstances.forEach(inst => { valueOld.add(inst.id); }); - if (JSON.stringify(Array.from(valueOld)) !== JSON.stringify(Array.from(valueNew))) { - const idsDel = this.diffBetweenSet(valueNew, this.deepCloneSet(valueOld)); - const idsAdd = this.diffBetweenSet(valueOld, this.deepCloneSet(valueNew)); + if (!isEqual(valueOld, valueNew)) { + const idsDel = this.diffBetweenSet(valueOld, valueNew); + const idsAdd = this.diffBetweenSet(valueNew, valueOld); if (idsAdd.size) { this.addInstancesNew(data.objectId, idsAdd); } if (idsDel.size) { - this.delInstances(data.objectId, idsDel); + this.deleteInstances(data.objectId, idsDel); } } } - private delInstances = (objectId: number, idsDel: Set): void => { - let isIdIndex = (element) => element.id === objectId; - const objectIndex = (this.observeAttrTelemetryFormGroup.get('clientLwM2M').value as ObjectLwM2M []).findIndex(isIdIndex); + private deleteInstances = (objectId: number, idsDel: Set): void => { + const objectIndex = (this.observeAttrTelemetryFormGroup.get('clientLwM2M').value as ObjectLwM2M[]) + .findIndex(element => element.id === objectId); idsDel.forEach(x => { - isIdIndex = (element) => element.value.id === x; const instancesFormArray = ((this.observeAttrTelemetryFormGroup.get('clientLwM2M') as FormArray) - .controls[objectIndex].get('instances') as FormArray); - const instanceIndex = instancesFormArray.controls.findIndex(isIdIndex); + .at(objectIndex).get('instances') as FormArray); + const instanceIndex = instancesFormArray.value.findIndex(element => element.id === x); instancesFormArray.removeAt(instanceIndex); }); } private addInstancesNew = (objectId: number, idsAdd: Set): void => { const instancesValue = (this.observeAttrTelemetryFormGroup.get('clientLwM2M').value as ObjectLwM2M []) - .find(e => e.id === objectId).instances; + .find(objectLwM2M => objectLwM2M.id === objectId).instances; const instancesFormArray = ((this.observeAttrTelemetryFormGroup.get('clientLwM2M') as FormArray).controls .find(e => e.value.id === objectId).get('instances') as FormArray) as FormArray; idsAdd.forEach(x => { const instanceNew = deepClone(instancesValue[0]) as Instance; - instanceNew.id = x; instanceNew.resources.forEach(r => { r.attribute = false; r.telemetry = false; @@ -322,28 +290,14 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor, }); instancesFormArray.push(this.fb.group({ id: x, - [this.observe]: {value: false, disabled: this.disabled}, - [this.attribute]: {value: false, disabled: this.disabled}, - [this.telemetry]: {value: false, disabled: this.disabled}, resources: {value: instanceNew.resources, disabled: this.disabled} })); }); (instancesFormArray.controls as FormGroup[]).sort((a, b) => a.value.id - b.value.id); } - private deepCloneSet = (oldSet: Set): Set => { - const newSet = new Set(); - oldSet.forEach(p => { - newSet.add(p); - }); - return newSet; - } - private diffBetweenSet = (firstSet: Set, secondSet: Set): Set => { - firstSet.forEach(p => { - secondSet.delete(p); - }); - return secondSet; + return new Set([...Array.from(firstSet)].filter(x => !secondSet.has(x))); } private setInstancesIds = (instances: Instance []): Set => { diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/profile-config.models.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/profile-config.models.ts index 1cbc1bdf03..681e2fa295 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/profile-config.models.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/profile-config.models.ts @@ -33,7 +33,6 @@ export const DEFAULT_BOOTSTRAP_SERVER_ACCOUNT_TIME_OUT = 0; export const LEN_MAX_PUBLIC_KEY_RPK = 182; export const LEN_MAX_PUBLIC_KEY_X509 = 3000; export const KEY_REGEXP_HEX_DEC = /^[-+]?[0-9A-Fa-f]+\.?[0-9A-Fa-f]*?$/; -export const CAMEL_CASE_REGEXP = /[-_&@.,*+!?^${}()|[\]\\]/g; export const INSTANCES_ID_VALUE_MIN = 0; export const INSTANCES_ID_VALUE_MAX = 65535; @@ -82,12 +81,14 @@ interface BootstrapSecurityConfig { export interface ProfileConfigModels { bootstrap: BootstrapSecurityConfig; - observeAttr: { - observe: string [], - attribute: string [], - telemetry: string [], - keyName: [] - }; + observeAttr: ObservableAttributes; +} + +export interface ObservableAttributes { + observe: string[]; + attribute: string[]; + telemetry: string[]; + keyName: string[]; } export function getDefaultBootstrapServersSecurityConfig(): BootstrapServersSecurityConfig { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-form.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-form.component.html index 19f6b87471..8340857d8d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-form.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-form.component.html @@ -35,7 +35,7 @@ required > -
profile-tab +
{{'gateway.security-type' | translate }} diff --git a/ui-ngx/src/app/shared/components/json-object-edit.component.ts b/ui-ngx/src/app/shared/components/json-object-edit.component.ts index c1b1e4ab06..61861bc6f6 100644 --- a/ui-ngx/src/app/shared/components/json-object-edit.component.ts +++ b/ui-ngx/src/app/shared/components/json-object-edit.component.ts @@ -61,8 +61,7 @@ export class JsonObjectEditComponent implements OnInit, ControlValueAccessor, Va @Input() editorStyle: { [klass: string]: any }; - // tslint:disable-next-line:ban-types - @Input() sort: Function; + @Input() sort: (key: string, value: any) => any; private requiredValue: boolean; @@ -227,10 +226,9 @@ export class JsonObjectEditComponent implements OnInit, ControlValueAccessor, Va try { if (this.modelValue) { - this.contentValue = JSON.stringify(this.modelValue, isUndefined(this.sort) ? null : - // tslint:disable-next-line:no-shadowed-variable - (key, value) => { - return this.sort(key, value); + this.contentValue = JSON.stringify(this.modelValue, isUndefined(this.sort) ? undefined : + (key, objectValue) => { + return this.sort(key, objectValue); }, 2); this.objectValid = true; } else { diff --git a/ui-ngx/src/app/shared/models/device.models.ts b/ui-ngx/src/app/shared/models/device.models.ts index 0f07cadd36..4ff9fadbba 100644 --- a/ui-ngx/src/app/shared/models/device.models.ts +++ b/ui-ngx/src/app/shared/models/device.models.ts @@ -454,8 +454,6 @@ export interface DeviceCredentials extends BaseData { credentialsType: DeviceCredentialsType; credentialsId: string; credentialsValue: string; - credentialsLwKey: string; - credentialsLwValue: string; } export interface DeviceCredentialMQTTBasic { From 9481654f5ba793ee4c2bdae8dbc0bcfb8fcd8926 Mon Sep 17 00:00:00 2001 From: Viacheslav Kukhtyn Date: Tue, 19 Jan 2021 20:32:18 +0200 Subject: [PATCH 044/249] Refactoring, deleting redundant classes --- .../credentials/AnonymousCredentials.java | 12 +++++- .../engine/credentials/BasicCredentials.java | 13 +++++- .../credentials/CertPemCredentials.java | 7 +++- .../ClientCredentials.java} | 21 ++++------ .../rule/engine/mqtt/TbMqttNode.java | 11 ++++- .../engine/mqtt/TbMqttNodeConfiguration.java | 8 ++-- .../mqtt/azure/AzureIotHubSasCredentials.java | 4 +- .../engine/mqtt/azure/TbAzureIotHubNode.java | 40 ++++++++----------- .../credentials/MqttAnonymousCredentials.java | 26 ------------ .../credentials/MqttBasicCredentials.java | 33 --------------- .../credentials/MqttCertPemCredentials.java | 26 ------------ .../rule/engine/rest/TbHttpClient.java | 24 ++++++----- .../rest/TbRestApiCallNodeConfiguration.java | 8 ++-- .../credentials/HttpAnonymousCredentials.java | 26 ------------ .../credentials/HttpBasicCredentials.java | 35 ---------------- .../credentials/HttpCertPemCredentials.java | 26 ------------ .../credentials/HttpClientCredentials.java | 32 --------------- ...alsTest.java => BasicCredentialsTest.java} | 10 ++--- 18 files changed, 92 insertions(+), 270 deletions(-) rename rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/{mqtt/credentials/MqttClientCredentials.java => credentials/ClientCredentials.java} (65%) delete mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttAnonymousCredentials.java delete mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttBasicCredentials.java delete mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttCertPemCredentials.java delete mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpAnonymousCredentials.java delete mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpBasicCredentials.java delete mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpCertPemCredentials.java delete mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/credentials/HttpClientCredentials.java rename rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/credentials/{HttpBasicCredentialsTest.java => BasicCredentialsTest.java} (76%) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/AnonymousCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/AnonymousCredentials.java index 1228256b30..133d08fe1c 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/AnonymousCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/AnonymousCredentials.java @@ -16,7 +16,17 @@ package org.thingsboard.rule.engine.credentials; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import io.netty.handler.ssl.SslContext; @JsonIgnoreProperties(ignoreUnknown = true) -public class AnonymousCredentials { +public class AnonymousCredentials implements ClientCredentials { + @Override + public CredentialsType getType() { + return CredentialsType.ANONYMOUS; + } + + @Override + public SslContext initSslContext() { + return null; + } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/BasicCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/BasicCredentials.java index 35287f4d73..b8901c5d54 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/BasicCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/BasicCredentials.java @@ -16,11 +16,22 @@ package org.thingsboard.rule.engine.credentials; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import io.netty.handler.ssl.SslContext; import lombok.Data; @Data @JsonIgnoreProperties(ignoreUnknown = true) -public class BasicCredentials { +public class BasicCredentials implements ClientCredentials { private String username; private String password; + + @Override + public CredentialsType getType() { + return CredentialsType.BASIC; + } + + @Override + public SslContext initSslContext() { + return null; + } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CertPemCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CertPemCredentials.java index 5aa1ede5e9..a1c40f0d24 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CertPemCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CertPemCredentials.java @@ -53,7 +53,7 @@ import java.security.spec.PKCS8EncodedKeySpec; @Data @Slf4j @JsonIgnoreProperties(ignoreUnknown = true) -public class CertPemCredentials { +public class CertPemCredentials implements ClientCredentials { private static final String TLS_VERSION = "TLSv1.2"; private String caCert; @@ -61,6 +61,11 @@ public class CertPemCredentials { private String privateKey; private String password; + @Override + public CredentialsType getType() { + return CredentialsType.CERT_PEM; + } + public SslContext initSslContext() { try { Security.addProvider(new BouncyCastleProvider()); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttClientCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/ClientCredentials.java similarity index 65% rename from rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttClientCredentials.java rename to rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/ClientCredentials.java index e7c72b2ee7..c30fe68895 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/credentials/MqttClientCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/ClientCredentials.java @@ -13,31 +13,24 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.rule.engine.mqtt.credentials; +package org.thingsboard.rule.engine.credentials; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; import io.netty.handler.ssl.SslContext; -import org.thingsboard.mqtt.MqttClientConfig; -import org.thingsboard.rule.engine.credentials.CredentialsType; import org.thingsboard.rule.engine.mqtt.azure.AzureIotHubSasCredentials; @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") @JsonSubTypes({ - @JsonSubTypes.Type(value = MqttAnonymousCredentials.class, name = "anonymous"), - @JsonSubTypes.Type(value = MqttBasicCredentials.class, name = "basic"), + @JsonSubTypes.Type(value = AnonymousCredentials.class, name = "anonymous"), + @JsonSubTypes.Type(value = BasicCredentials.class, name = "basic"), @JsonSubTypes.Type(value = AzureIotHubSasCredentials.class, name = "sas"), - @JsonSubTypes.Type(value = MqttCertPemCredentials.class, name = "cert.PEM")}) -public interface MqttClientCredentials { + @JsonSubTypes.Type(value = CertPemCredentials.class, name = "cert.PEM")}) +public interface ClientCredentials { @JsonIgnore CredentialsType getType(); - default SslContext initSslContext() { - return null; - } - - default void configure(MqttClientConfig config) { - } + @JsonIgnore + SslContext initSslContext(); } - diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java index 47b950554a..89df78b148 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java @@ -31,6 +31,9 @@ import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.rule.engine.credentials.BasicCredentials; +import org.thingsboard.rule.engine.credentials.ClientCredentials; +import org.thingsboard.rule.engine.credentials.CredentialsType; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -105,7 +108,13 @@ public class TbMqttNode implements TbNode { config.setClientId(this.mqttNodeConfiguration.getClientId()); } config.setCleanSession(this.mqttNodeConfiguration.isCleanSession()); - this.mqttNodeConfiguration.getCredentials().configure(config); + + ClientCredentials credentials = this.mqttNodeConfiguration.getCredentials(); + if (credentials.getType() == CredentialsType.BASIC) { + config.setUsername(((BasicCredentials) credentials).getUsername()); + config.setPassword(((BasicCredentials) credentials).getPassword()); + } + MqttClient client = MqttClient.create(config, null); client.setEventLoop(ctx.getSharedEventLoop()); Future connectFuture = client.connect(this.mqttNodeConfiguration.getHost(), this.mqttNodeConfiguration.getPort()); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeConfiguration.java index d8d265f9c6..e06824180e 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeConfiguration.java @@ -17,8 +17,8 @@ package org.thingsboard.rule.engine.mqtt; import lombok.Data; import org.thingsboard.rule.engine.api.NodeConfiguration; -import org.thingsboard.rule.engine.mqtt.credentials.MqttAnonymousCredentials; -import org.thingsboard.rule.engine.mqtt.credentials.MqttClientCredentials; +import org.thingsboard.rule.engine.credentials.AnonymousCredentials; +import org.thingsboard.rule.engine.credentials.ClientCredentials; @Data public class TbMqttNodeConfiguration implements NodeConfiguration { @@ -31,7 +31,7 @@ public class TbMqttNodeConfiguration implements NodeConfiguration headers.add(TbNodeUtils.processPattern(k, metaData), TbNodeUtils.processPattern(v, metaData))); - addAuthorizationHeader(headers); + getBasicAuthHeaderValue(config.getCredentials()).ifPresent(authString -> headers.add("Authorization", authString)); return headers; } @@ -278,10 +281,13 @@ public class TbHttpClient { } } - private void addAuthorizationHeader(HttpHeaders headers) { - HttpClientCredentials credentials = config.getCredentials(); + public static Optional getBasicAuthHeaderValue(ClientCredentials credentials) { if (CredentialsType.BASIC == credentials.getType()) { - headers.add("Authorization", ((HttpBasicCredentials) credentials).getBasicAuthHeaderValue()); + BasicCredentials basicCredentials = (BasicCredentials) credentials; + String authString = basicCredentials.getUsername() + ":" + basicCredentials.getPassword(); + String encodedAuthString = new String(Base64.encodeBase64(authString.getBytes(StandardCharsets.UTF_8))); + return Optional.of("Basic " + encodedAuthString); } + return Optional.empty(); } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbRestApiCallNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbRestApiCallNodeConfiguration.java index 38936244ae..40b79163b8 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbRestApiCallNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbRestApiCallNodeConfiguration.java @@ -18,8 +18,8 @@ package org.thingsboard.rule.engine.rest; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; import org.thingsboard.rule.engine.api.NodeConfiguration; -import org.thingsboard.rule.engine.rest.credentials.HttpAnonymousCredentials; -import org.thingsboard.rule.engine.rest.credentials.HttpClientCredentials; +import org.thingsboard.rule.engine.credentials.AnonymousCredentials; +import org.thingsboard.rule.engine.credentials.ClientCredentials; import java.util.Collections; import java.util.Map; @@ -44,7 +44,7 @@ public class TbRestApiCallNodeConfiguration implements NodeConfiguration Date: Tue, 19 Jan 2021 23:50:52 +0200 Subject: [PATCH 045/249] Add default SSL context for all credentials types --- .../credentials/AnonymousCredentials.java | 6 ------ .../engine/credentials/BasicCredentials.java | 6 ------ .../engine/credentials/ClientCredentials.java | 7 ++++++- .../rule/engine/mqtt/TbMqttNode.java | 9 +++++---- .../engine/mqtt/azure/TbAzureIotHubNode.java | 4 +++- .../rule/engine/rest/TbHttpClient.java | 17 +---------------- 6 files changed, 15 insertions(+), 34 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/AnonymousCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/AnonymousCredentials.java index 133d08fe1c..6670254fd1 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/AnonymousCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/AnonymousCredentials.java @@ -16,7 +16,6 @@ package org.thingsboard.rule.engine.credentials; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import io.netty.handler.ssl.SslContext; @JsonIgnoreProperties(ignoreUnknown = true) public class AnonymousCredentials implements ClientCredentials { @@ -24,9 +23,4 @@ public class AnonymousCredentials implements ClientCredentials { public CredentialsType getType() { return CredentialsType.ANONYMOUS; } - - @Override - public SslContext initSslContext() { - return null; - } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/BasicCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/BasicCredentials.java index b8901c5d54..c958d9300f 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/BasicCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/BasicCredentials.java @@ -16,7 +16,6 @@ package org.thingsboard.rule.engine.credentials; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import io.netty.handler.ssl.SslContext; import lombok.Data; @Data @@ -29,9 +28,4 @@ public class BasicCredentials implements ClientCredentials { public CredentialsType getType() { return CredentialsType.BASIC; } - - @Override - public SslContext initSslContext() { - return null; - } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/ClientCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/ClientCredentials.java index c30fe68895..8f4b20a5c4 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/ClientCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/ClientCredentials.java @@ -19,8 +19,11 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; import io.netty.handler.ssl.SslContext; +import io.netty.handler.ssl.SslContextBuilder; import org.thingsboard.rule.engine.mqtt.azure.AzureIotHubSasCredentials; +import javax.net.ssl.SSLException; + @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") @JsonSubTypes({ @JsonSubTypes.Type(value = AnonymousCredentials.class, name = "anonymous"), @@ -32,5 +35,7 @@ public interface ClientCredentials { CredentialsType getType(); @JsonIgnore - SslContext initSslContext(); + default SslContext initSslContext() throws SSLException{ + return SslContextBuilder.forClient().build(); + } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java index 89df78b148..ba1d0caea2 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java @@ -18,7 +18,6 @@ package org.thingsboard.rule.engine.mqtt; import io.netty.buffer.Unpooled; import io.netty.handler.codec.mqtt.MqttQoS; import io.netty.handler.ssl.SslContext; -import io.netty.handler.ssl.SslContextBuilder; import io.netty.util.concurrent.Future; import lombok.extern.slf4j.Slf4j; import org.springframework.util.StringUtils; @@ -137,9 +136,11 @@ public class TbMqttNode implements TbNode { } private SslContext getSslContext() throws SSLException { - SslContext sslContext = this.mqttNodeConfiguration.getCredentials().initSslContext(); - if (this.mqttNodeConfiguration.isSsl() && sslContext == null) { - sslContext = SslContextBuilder.forClient().build(); + ClientCredentials credentials = this.mqttNodeConfiguration.getCredentials(); + SslContext sslContext = credentials.initSslContext(); + if (!this.mqttNodeConfiguration.isSsl() && + (credentials.getType() == CredentialsType.ANONYMOUS || credentials.getType() == CredentialsType.BASIC)) { + sslContext = null; } return sslContext; } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNode.java index 8c56466d5b..4ada1e0d39 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNode.java @@ -30,6 +30,8 @@ import org.thingsboard.rule.engine.mqtt.TbMqttNode; import org.thingsboard.rule.engine.mqtt.TbMqttNodeConfiguration; import org.thingsboard.server.common.data.plugin.ComponentType; +import javax.net.ssl.SSLException; + @Slf4j @RuleNode( type = ComponentType.EXTERNAL, @@ -55,7 +57,7 @@ public class TbAzureIotHubNode extends TbMqttNode { } @Override - public SslContext initSslContext() { + public SslContext initSslContext() throws SSLException { if (credentials instanceof AzureIotHubSasCredentials) { AzureIotHubSasCredentials sasCredentials = (AzureIotHubSasCredentials) credentials; if (sasCredentials.getCaCert() == null || sasCredentials.getCaCert().isEmpty()) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java index 9bb6363d00..a2921029bc 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java @@ -17,8 +17,6 @@ package org.thingsboard.rule.engine.rest; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.handler.ssl.SslContext; -import io.netty.handler.ssl.SslContextBuilder; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.binary.Base64; @@ -47,7 +45,6 @@ import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.TbRelationTypes; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.credentials.BasicCredentials; -import org.thingsboard.rule.engine.credentials.CertPemCredentials; import org.thingsboard.rule.engine.credentials.ClientCredentials; import org.thingsboard.rule.engine.credentials.CredentialsType; import org.thingsboard.server.common.msg.TbMsg; @@ -141,7 +138,7 @@ public class TbHttpClient { } else { this.eventLoopGroup = new NioEventLoopGroup(); Netty4ClientHttpRequestFactory nettyFactory = new Netty4ClientHttpRequestFactory(this.eventLoopGroup); - nettyFactory.setSslContext(getSslContext(config.getCredentials())); + nettyFactory.setSslContext(config.getCredentials().initSslContext()); nettyFactory.setReadTimeout(config.getReadTimeoutMs()); httpClient = new AsyncRestTemplate(nettyFactory); } @@ -150,18 +147,6 @@ public class TbHttpClient { } } - private SslContext getSslContext(ClientCredentials credentials) throws SSLException { - switch (credentials.getType()) { - case ANONYMOUS: - case BASIC: - return SslContextBuilder.forClient().build(); - case CERT_PEM: - return credentials.initSslContext(); - default: - throw new IllegalArgumentException("[" + credentials.getType() + "] is not supported!"); - } - } - private void checkSystemProxyProperties() throws TbNodeException { boolean useHttpProxy = !StringUtils.isEmpty(System.getProperty("http.proxyHost")) && !StringUtils.isEmpty(System.getProperty("http.proxyPort")); boolean useHttpsProxy = !StringUtils.isEmpty(System.getProperty("https.proxyHost")) && !StringUtils.isEmpty(System.getProperty("https.proxyPort")); From 6cfc79215608b3c08e09f653e76c647eb4f455be Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 20 Jan 2021 09:12:05 +0200 Subject: [PATCH 046/249] Lwm2m: front: refactoring --- ...ile-transport-configuration.component.html | 35 +++++++++++-------- .../lwm2m/security-config.component.html | 34 ++++++++++-------- 2 files changed, 40 insertions(+), 29 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html index 58eaff4fdc..7b49f8ffd6 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html @@ -60,7 +60,8 @@ {{ 'device-profile.lwm2m.lifetime' | translate }} - + {{ 'device-profile.lwm2m.lifetime' | translate }} {{ 'device-profile.lwm2m.required' | translate }} @@ -102,13 +103,15 @@ class="tb-panel-title">{{ 'device-profile.lwm2m.bootstrap-server' | translate | uppercase }}
-
- - -
+ +
+ + +
+
@@ -118,13 +121,15 @@
{{ 'device-profile.lwm2m.lwm2m-server' | translate | uppercase }}
-
- - -
+ +
+ + +
+
diff --git a/ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config.component.html b/ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config.component.html index f5e52d41fc..e2b95cdb73 100644 --- a/ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config.component.html +++ b/ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config.component.html @@ -83,13 +83,15 @@ {{ 'device.lwm2m-security-config.client-key' | translate }} {{ translate.get('device.lwm2m-security-config.pattern_hex_dec', { - count: 0 }) | async }} + count: 0 + }) | async }} {{ 'device.lwm2m-security-config.client-key' | translate }} {{ translate.get('device.lwm2m-security-config.pattern_hex_dec', { - count: lenMaxKeyClient }) | async }} + count: lenMaxKeyClient + }) | async }}
@@ -112,12 +114,14 @@ class="tb-panel-title">{{ 'device.lwm2m-security-config.bootstrap-server' | translate | uppercase }}
-
- - -
+ +
+ + +
+
@@ -128,12 +132,14 @@ class="tb-panel-title">{{ 'device.lwm2m-security-config.lwm2m-server' | translate | uppercase }}
-
- - -
+ +
+ + +
+
From b2b09b3010b75ec5cfae6142a934b2984c673d25 Mon Sep 17 00:00:00 2001 From: zbeacon Date: Wed, 20 Jan 2021 10:32:32 +0200 Subject: [PATCH 047/249] Improvements --- .../mqtt/session/GatewayDeviceSessionCtx.java | 11 ----- .../mqtt/session/GatewaySessionHandler.java | 3 -- .../transport/auth/SessionInfoCreator.java | 22 ++++++++-- .../service/DefaultTransportService.java | 41 +++++++++++++++++-- 4 files changed, 55 insertions(+), 22 deletions(-) diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java index db9ea66c44..60a2503225 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java @@ -15,8 +15,6 @@ */ package org.thingsboard.server.transport.mqtt.session; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.transport.SessionMsgListener; @@ -39,14 +37,6 @@ public class GatewayDeviceSessionCtx extends MqttDeviceAwareSessionContext imple DeviceProfile deviceProfile, ConcurrentMap mqttQoSMap) { super(UUID.randomUUID(), mqttQoSMap); this.parent = parent; - JsonParser parser = new JsonParser(); - boolean activityTimeFromGatewayDevice = Boolean.FALSE; - if (this.parent.getDeviceInfo().getAdditionalInfo() != null && !"null".equals(this.parent.getDeviceInfo().getAdditionalInfo())) { - JsonObject additionalInfo = parser.parse(this.parent.getDeviceInfo().getAdditionalInfo()).getAsJsonObject(); - if (additionalInfo.get("activityTimeFromGatewayDevice") != null) { - activityTimeFromGatewayDevice = additionalInfo.get("activityTimeFromGatewayDevice").getAsBoolean(); - } - } setSessionInfo(SessionInfoProto.newBuilder() .setNodeId(parent.getNodeId()) .setSessionIdMSB(sessionId.getMostSignificantBits()) @@ -61,7 +51,6 @@ public class GatewayDeviceSessionCtx extends MqttDeviceAwareSessionContext imple .setGwSessionIdLSB(parent.getSessionId().getLeastSignificantBits()) .setDeviceProfileIdMSB(deviceInfo.getDeviceProfileId().getId().getMostSignificantBits()) .setDeviceProfileIdLSB(deviceInfo.getDeviceProfileId().getId().getLeastSignificantBits()) - .setActivityTimeFromGatewayDevice(activityTimeFromGatewayDevice) .build()); setDeviceInfo(deviceInfo); setDeviceProfile(deviceProfile); diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewaySessionHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewaySessionHandler.java index 15986b930e..73c7347039 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewaySessionHandler.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewaySessionHandler.java @@ -34,7 +34,6 @@ import io.netty.handler.codec.mqtt.MqttPublishMessage; import lombok.extern.slf4j.Slf4j; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; -import org.thingsboard.server.common.data.DeviceInfo; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.common.transport.TransportServiceCallback; @@ -180,8 +179,6 @@ public class GatewaySessionHandler { return deviceSessionCtx.getPayloadAdaptor(); } - public TransportDeviceInfo getDeviceInfo() { return deviceSessionCtx.getDeviceInfo(); } - void deregisterSession(String deviceName) { GatewayDeviceSessionCtx deviceSessionCtx = devices.remove(deviceName); if (deviceSessionCtx != null) { diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/auth/SessionInfoCreator.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/auth/SessionInfoCreator.java index 235ae6b3a3..cf07f65010 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/auth/SessionInfoCreator.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/auth/SessionInfoCreator.java @@ -15,16 +15,20 @@ */ package org.thingsboard.server.common.transport.auth; +import com.fasterxml.jackson.databind.JsonNode; +import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.common.transport.TransportContext; import org.thingsboard.server.gen.transport.TransportProtos; +import java.io.IOException; import java.util.UUID; +@Slf4j public class SessionInfoCreator { public static TransportProtos.SessionInfoProto create(ValidateDeviceCredentialsResponse msg, TransportContext context, UUID sessionId) { - return TransportProtos.SessionInfoProto.newBuilder() - .setNodeId(context.getNodeId()) + TransportProtos.SessionInfoProto.Builder builder = TransportProtos.SessionInfoProto.newBuilder(); + builder.setNodeId(context.getNodeId()) .setSessionIdMSB(sessionId.getMostSignificantBits()) .setSessionIdLSB(sessionId.getLeastSignificantBits()) .setDeviceIdMSB(msg.getDeviceInfo().getDeviceId().getId().getMostSignificantBits()) @@ -34,8 +38,18 @@ public class SessionInfoCreator { .setDeviceName(msg.getDeviceInfo().getDeviceName()) .setDeviceType(msg.getDeviceInfo().getDeviceType()) .setDeviceProfileIdMSB(msg.getDeviceInfo().getDeviceProfileId().getId().getMostSignificantBits()) - .setDeviceProfileIdLSB(msg.getDeviceInfo().getDeviceProfileId().getId().getLeastSignificantBits()) - .build(); + .setDeviceProfileIdLSB(msg.getDeviceInfo().getDeviceProfileId().getId().getLeastSignificantBits()); + if (!"null".equals(msg.getDeviceInfo().getAdditionalInfo())) { + try { + JsonNode infoNode = context.getMapper().readTree(msg.getDeviceInfo().getAdditionalInfo()); + if (infoNode.get("gateway").asBoolean()) { + builder.setActivityTimeFromGatewayDevice(infoNode.get("activityTimeFromGatewayDevice").asBoolean()); + } + } catch (IOException e) { + log.trace("[{}][{}] Failed to fetch device additional info", sessionId, msg.getDeviceInfo().getDeviceName(), e); + } + } + return builder.build(); } } diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java index 472cffef30..df1807cc0d 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java @@ -61,6 +61,7 @@ import org.thingsboard.server.common.transport.util.JsonUtils; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceResponseMsg; +import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; @@ -510,10 +511,9 @@ public class DefaultTransportService implements TransportService { long lastActivityTime = sessionMD.getLastActivityTime(); TransportProtos.SessionInfoProto sessionInfo = sessionMD.getSessionInfo(); if (sessionInfo.getGwSessionIdMSB() != 0 && - sessionInfo.getGwSessionIdLSB() != 0 && - sessionInfo.getActivityTimeFromGatewayDevice()) { + sessionInfo.getGwSessionIdLSB() != 0) { SessionMetaData gwMetaData = sessions.get(new UUID(sessionInfo.getGwSessionIdMSB(), sessionInfo.getGwSessionIdLSB())); - if (gwMetaData != null) { + if (gwMetaData != null && gwMetaData.getSessionInfo().getActivityTimeFromGatewayDevice()) { lastActivityTime = Math.max(gwMetaData.getLastActivityTime(), lastActivityTime); } } @@ -647,7 +647,40 @@ public class DefaultTransportService implements TransportService { } } else if (EntityType.DEVICE.equals(entityType)) { Optional deviceOpt = dataDecodingEncodingService.decode(msg.getData().toByteArray()); - deviceOpt.ifPresent(this::onDeviceUpdate); + if (deviceOpt.isPresent()) { + Device device = deviceOpt.get(); + if (device.getAdditionalInfo() != null) { + if (device.getAdditionalInfo().get("gateway") != null + && device.getAdditionalInfo().get("gateway").asBoolean()) { + sessions.forEach((uuid, currentMD) -> { + if (device.getId().equals(new DeviceId(new UUID(currentMD.getSessionInfo().getDeviceIdMSB(), currentMD.getSessionInfo().getDeviceIdLSB())))) { + boolean newActivityTimeFromGatewayDevice = device.getAdditionalInfo().get("activityTimeFromGatewayDevice").asBoolean(); + if (currentMD.getSessionInfo().getActivityTimeFromGatewayDevice() != newActivityTimeFromGatewayDevice) { + SessionInfoProto currentSessionInfo = currentMD.getSessionInfo(); + SessionInfoProto newSessionInfo = SessionInfoProto.newBuilder() + .setNodeId(currentSessionInfo.getNodeId()) + .setSessionIdMSB(currentSessionInfo.getSessionIdMSB()) + .setSessionIdLSB(currentSessionInfo.getSessionIdLSB()) + .setDeviceIdMSB(currentSessionInfo.getDeviceIdMSB()) + .setDeviceIdLSB(currentSessionInfo.getDeviceIdLSB()) + .setTenantIdMSB(currentSessionInfo.getTenantIdMSB()) + .setTenantIdLSB(currentSessionInfo.getTenantIdLSB()) + .setDeviceName(currentSessionInfo.getDeviceName()) + .setDeviceType(currentSessionInfo.getDeviceType()) + .setGwSessionIdMSB(currentSessionInfo.getGwSessionIdMSB()) + .setGwSessionIdLSB(currentSessionInfo.getGwSessionIdLSB()) + .setDeviceProfileIdMSB(currentSessionInfo.getDeviceProfileIdMSB()) + .setDeviceProfileIdLSB(currentSessionInfo.getDeviceProfileIdLSB()) + .setActivityTimeFromGatewayDevice(newActivityTimeFromGatewayDevice) + .build(); + currentMD.setSessionInfo(newSessionInfo); + } + } + }); + } + } + onDeviceUpdate(device); + } } } else if (toSessionMsg.hasEntityDeleteMsg()) { TransportProtos.EntityDeleteMsg msg = toSessionMsg.getEntityDeleteMsg(); From 5338d8e094c93ea69fbfdfdf9332d47724eb5226 Mon Sep 17 00:00:00 2001 From: zbeacon Date: Wed, 20 Jan 2021 11:44:27 +0200 Subject: [PATCH 048/249] Refactoring --- .../transport/auth/SessionInfoCreator.java | 8 ++- .../service/DefaultTransportService.java | 53 +++++++++---------- 2 files changed, 31 insertions(+), 30 deletions(-) diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/auth/SessionInfoCreator.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/auth/SessionInfoCreator.java index cf07f65010..793afa97d7 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/auth/SessionInfoCreator.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/auth/SessionInfoCreator.java @@ -42,8 +42,12 @@ public class SessionInfoCreator { if (!"null".equals(msg.getDeviceInfo().getAdditionalInfo())) { try { JsonNode infoNode = context.getMapper().readTree(msg.getDeviceInfo().getAdditionalInfo()); - if (infoNode.get("gateway").asBoolean()) { - builder.setActivityTimeFromGatewayDevice(infoNode.get("activityTimeFromGatewayDevice").asBoolean()); + if (infoNode.get("gateway").asBoolean(false)) { + boolean activityTimeFromGatewayDevice = false; + if (infoNode.get("activityTimeFromGatewayDevice") != null) { + activityTimeFromGatewayDevice = infoNode.get("activityTimeFromGatewayDevice").asBoolean(); + } + builder.setActivityTimeFromGatewayDevice(activityTimeFromGatewayDevice); } } catch (IOException e) { log.trace("[{}][{}] Failed to fetch device additional info", sessionId, msg.getDeviceInfo().getDeviceName(), e); diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java index df1807cc0d..4b41313b7e 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java @@ -649,35 +649,32 @@ public class DefaultTransportService implements TransportService { Optional deviceOpt = dataDecodingEncodingService.decode(msg.getData().toByteArray()); if (deviceOpt.isPresent()) { Device device = deviceOpt.get(); - if (device.getAdditionalInfo() != null) { - if (device.getAdditionalInfo().get("gateway") != null - && device.getAdditionalInfo().get("gateway").asBoolean()) { - sessions.forEach((uuid, currentMD) -> { - if (device.getId().equals(new DeviceId(new UUID(currentMD.getSessionInfo().getDeviceIdMSB(), currentMD.getSessionInfo().getDeviceIdLSB())))) { - boolean newActivityTimeFromGatewayDevice = device.getAdditionalInfo().get("activityTimeFromGatewayDevice").asBoolean(); - if (currentMD.getSessionInfo().getActivityTimeFromGatewayDevice() != newActivityTimeFromGatewayDevice) { - SessionInfoProto currentSessionInfo = currentMD.getSessionInfo(); - SessionInfoProto newSessionInfo = SessionInfoProto.newBuilder() - .setNodeId(currentSessionInfo.getNodeId()) - .setSessionIdMSB(currentSessionInfo.getSessionIdMSB()) - .setSessionIdLSB(currentSessionInfo.getSessionIdLSB()) - .setDeviceIdMSB(currentSessionInfo.getDeviceIdMSB()) - .setDeviceIdLSB(currentSessionInfo.getDeviceIdLSB()) - .setTenantIdMSB(currentSessionInfo.getTenantIdMSB()) - .setTenantIdLSB(currentSessionInfo.getTenantIdLSB()) - .setDeviceName(currentSessionInfo.getDeviceName()) - .setDeviceType(currentSessionInfo.getDeviceType()) - .setGwSessionIdMSB(currentSessionInfo.getGwSessionIdMSB()) - .setGwSessionIdLSB(currentSessionInfo.getGwSessionIdLSB()) - .setDeviceProfileIdMSB(currentSessionInfo.getDeviceProfileIdMSB()) - .setDeviceProfileIdLSB(currentSessionInfo.getDeviceProfileIdLSB()) - .setActivityTimeFromGatewayDevice(newActivityTimeFromGatewayDevice) - .build(); - currentMD.setSessionInfo(newSessionInfo); - } + if (device.getAdditionalInfo().get("gateway") != null && device.getAdditionalInfo().get("gateway").asBoolean()) { + sessions.forEach((uuid, currentMD) -> { + if (device.getId().equals(new DeviceId(new UUID(currentMD.getSessionInfo().getDeviceIdMSB(), currentMD.getSessionInfo().getDeviceIdLSB())))) { + boolean newActivityTimeFromGatewayDevice = device.getAdditionalInfo().get("activityTimeFromGatewayDevice").asBoolean(false); + if (currentMD.getSessionInfo().getActivityTimeFromGatewayDevice() != newActivityTimeFromGatewayDevice) { + SessionInfoProto currentSessionInfo = currentMD.getSessionInfo(); + SessionInfoProto newSessionInfo = SessionInfoProto.newBuilder() + .setNodeId(currentSessionInfo.getNodeId()) + .setSessionIdMSB(currentSessionInfo.getSessionIdMSB()) + .setSessionIdLSB(currentSessionInfo.getSessionIdLSB()) + .setDeviceIdMSB(currentSessionInfo.getDeviceIdMSB()) + .setDeviceIdLSB(currentSessionInfo.getDeviceIdLSB()) + .setTenantIdMSB(currentSessionInfo.getTenantIdMSB()) + .setTenantIdLSB(currentSessionInfo.getTenantIdLSB()) + .setDeviceName(currentSessionInfo.getDeviceName()) + .setDeviceType(currentSessionInfo.getDeviceType()) + .setGwSessionIdMSB(currentSessionInfo.getGwSessionIdMSB()) + .setGwSessionIdLSB(currentSessionInfo.getGwSessionIdLSB()) + .setDeviceProfileIdMSB(currentSessionInfo.getDeviceProfileIdMSB()) + .setDeviceProfileIdLSB(currentSessionInfo.getDeviceProfileIdLSB()) + .setActivityTimeFromGatewayDevice(newActivityTimeFromGatewayDevice) + .build(); + currentMD.setSessionInfo(newSessionInfo); } - }); - } + } + }); } onDeviceUpdate(device); } From c24db73a37cd54296bf6258010b510918ce7363a Mon Sep 17 00:00:00 2001 From: zbeacon Date: Wed, 20 Jan 2021 12:41:35 +0200 Subject: [PATCH 049/249] Refactoring --- .../server/common/transport/auth/SessionInfoCreator.java | 4 ++-- .../common/transport/service/DefaultTransportService.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/auth/SessionInfoCreator.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/auth/SessionInfoCreator.java index 793afa97d7..ee4d8343a8 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/auth/SessionInfoCreator.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/auth/SessionInfoCreator.java @@ -42,9 +42,9 @@ public class SessionInfoCreator { if (!"null".equals(msg.getDeviceInfo().getAdditionalInfo())) { try { JsonNode infoNode = context.getMapper().readTree(msg.getDeviceInfo().getAdditionalInfo()); - if (infoNode.get("gateway").asBoolean(false)) { + if (infoNode.get("gateway").asBoolean()) { boolean activityTimeFromGatewayDevice = false; - if (infoNode.get("activityTimeFromGatewayDevice") != null) { + if (infoNode.has("activityTimeFromGatewayDevice")) { activityTimeFromGatewayDevice = infoNode.get("activityTimeFromGatewayDevice").asBoolean(); } builder.setActivityTimeFromGatewayDevice(activityTimeFromGatewayDevice); diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java index 4b41313b7e..86b49f4915 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java @@ -649,10 +649,10 @@ public class DefaultTransportService implements TransportService { Optional deviceOpt = dataDecodingEncodingService.decode(msg.getData().toByteArray()); if (deviceOpt.isPresent()) { Device device = deviceOpt.get(); - if (device.getAdditionalInfo().get("gateway") != null && device.getAdditionalInfo().get("gateway").asBoolean()) { + if (device.getAdditionalInfo().has("gateway") && device.getAdditionalInfo().get("gateway").asBoolean()) { sessions.forEach((uuid, currentMD) -> { if (device.getId().equals(new DeviceId(new UUID(currentMD.getSessionInfo().getDeviceIdMSB(), currentMD.getSessionInfo().getDeviceIdLSB())))) { - boolean newActivityTimeFromGatewayDevice = device.getAdditionalInfo().get("activityTimeFromGatewayDevice").asBoolean(false); + boolean newActivityTimeFromGatewayDevice = device.getAdditionalInfo().get("activityTimeFromGatewayDevice").asBoolean(); if (currentMD.getSessionInfo().getActivityTimeFromGatewayDevice() != newActivityTimeFromGatewayDevice) { SessionInfoProto currentSessionInfo = currentMD.getSessionInfo(); SessionInfoProto newSessionInfo = SessionInfoProto.newBuilder() From e6a3ee272581a599c45d50cc0546b0832f211138 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Wed, 20 Jan 2021 16:19:58 +0200 Subject: [PATCH 050/249] UI: Refactoring lwm2m --- .../lwm2m-device-config-server.component.ts | 27 ++-- ...ofile-transport-configuration.component.ts | 21 ++- ...m-object-add-instances-list.component.html | 81 +++++------ ...m-object-add-instances-list.component.scss | 22 --- ...m2m-object-add-instances-list.component.ts | 127 ++++-------------- .../lwm2m-object-add-instances.component.html | 8 +- .../lwm2m/lwm2m-object-list.component.html | 4 +- .../lwm2m/lwm2m-object-list.component.ts | 53 +++----- .../lwm2m-observe-attr-telemetry.component.ts | 49 +++---- .../device/lwm2m/profile-config.models.ts | 1 + 10 files changed, 129 insertions(+), 264 deletions(-) delete mode 100644 ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.scss diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts index 29589d2388..fc766683f2 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Inject, Input, OnInit } from '@angular/core'; +import { Component, forwardRef, Inject, Input } from '@angular/core'; import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; import { DEFAULT_CLIENT_HOLD_OFF_TIME, @@ -48,7 +48,7 @@ import { TranslateService } from '@ngx-translate/core'; ] }) -export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAccessor, Validators { +export class Lwm2mDeviceConfigServerComponent implements ControlValueAccessor { private requiredValue: boolean; @@ -82,7 +82,7 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc public fb: FormBuilder, private deviceProfileService: DeviceProfileService, @Inject(WINDOW) private window: Window) { - this.serverFormGroup = this.getServerGroup(); + this.serverFormGroup = this.initServerGroup(); this.serverFormGroup.get('securityMode').valueChanges.pipe( startWith(null), pairwise() @@ -101,9 +101,6 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc }); } - ngOnInit(): void { - } - private updateValueFields = (serverData: ServerSecurityConfig): void => { serverData.bootstrapServerIs = this.bootstrapServerIs; this.serverFormGroup.patchValue(serverData, {emitEvent: false}); @@ -187,17 +184,17 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc registerOnTouched(fn: any): void { } - private getServerGroup = (): FormGroup => { + private initServerGroup = (): FormGroup => { const port = this.bootstrapServerIs ? DEFAULT_PORT_BOOTSTRAP_NO_SEC : DEFAULT_PORT_SERVER_NO_SEC; return this.fb.group({ - host: [this.window.location.hostname, this.required ? [Validators.required] : []], - port: [port, this.required ? [Validators.required] : []], - bootstrapServerIs: [this.bootstrapServerIs, []], - securityMode: [this.fb.control(SECURITY_CONFIG_MODE.NO_SEC), []], - serverPublicKey: ['', this.required ? [Validators.required] : []], - clientHoldOffTime: [DEFAULT_CLIENT_HOLD_OFF_TIME, this.required ? [Validators.required] : []], - serverId: [DEFAULT_ID_SERVER, this.required ? [Validators.required] : []], - bootstrapServerAccountTimeout: ['', this.required ? [Validators.required] : []], + host: [this.window.location.hostname, this.required ? Validators.required : ''], + port: [port, this.required ? Validators.required : ''], + bootstrapServerIs: [this.bootstrapServerIs, ''], + securityMode: [this.fb.control(SECURITY_CONFIG_MODE.NO_SEC)], + serverPublicKey: ['', this.required ? Validators.required : ''], + clientHoldOffTime: [DEFAULT_CLIENT_HOLD_OFF_TIME, this.required ? Validators.required : ''], + serverId: [DEFAULT_ID_SERVER, this.required ? Validators.required : ''], + bootstrapServerAccountTimeout: ['', this.required ? Validators.required : ''], }); } diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts index ea7da72966..feb248d5cc 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts @@ -15,7 +15,7 @@ /// import { DeviceProfileTransportConfiguration, DeviceTransportType } from '@shared/models/device.models'; -import { Component, forwardRef, Inject, Input, OnInit } from '@angular/core'; +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'; @@ -54,11 +54,11 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro private disabled = false; lwm2mDeviceProfileTransportConfFormGroup: FormGroup; - observeAttr = OBSERVE_ATTR as string; - observe = OBSERVE as string; - attribute = ATTR as string; - telemetry = TELEMETRY as string; - keyName = KEY_NAME as string; + observeAttr = OBSERVE_ATTR; + observe = OBSERVE; + attribute = ATTR; + telemetry = TELEMETRY; + keyName = KEY_NAME; bootstrapServers: string; bootstrapServer: string; lwm2mServer: string; @@ -73,7 +73,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro this.requiredValue = coerceBooleanProperty(value); } - private propagateChange = (v: any) => { }; + private propagateChange = (v: any) => { }; constructor(private store: Store, private fb: FormBuilder, @@ -81,7 +81,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro @Inject(WINDOW) private window: Window) { this.lwm2mDeviceProfileTransportConfFormGroup = this.fb.group({ objectIds: [{}, Validators.required], - observeAttrTelemetry: [{clientLwM2M: [] as ObjectLwM2M[]}, Validators.required], + observeAttrTelemetry: [{clientLwM2M: []}, Validators.required], shortId: [null, Validators.required], lifetime: [null, Validators.required], defaultMinPeriod: [null, Validators.required], @@ -116,12 +116,11 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } writeValue(value: any | null): void { - value = (Object.keys(value).length === 0) ? getDefaultProfileConfig() : value; + this.configurationValue = (Object.keys(value).length === 0) ? getDefaultProfileConfig() : value; this.lwm2mDeviceProfileTransportConfFormGroup.patchValue({ - configurationJson: value + configurationJson: this.configurationValue }, {emitEvent: false}); - this.configurationValue = this.lwm2mDeviceProfileTransportConfFormGroup.getRawValue().configurationJson; this.initWriteValue(); } diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.html index cddc6f1ef5..5a03f3f54d 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.html @@ -15,43 +15,46 @@ limitations under the License. --> - - {{ 'device-profile.lwm2m.instances-list' | translate }} - - - {{instanceIdInputFor}} - close - - - {{ 'device-profile.lwm2m.instances-input' | translate }} - - - {{ translate.get('device-profile.lwm2m.valid-id-instance-no-min', { - instance: instanceIdInput.value.toString(), min: instanceIdValueMin.toString() - }) | async }} - - - {{ translate.get('device-profile.lwm2m.valid-id-instance-no-max', { - instance: instanceIdInput.value.toString(), max: instanceIdValueMax.toString() - }) | async }} - - - {{ translate.get('device-profile.lwm2m.instances-input-holder', { - instance: instanceIdInput.value.toString(), max: instanceIdValueMax.toString() - }) | async }} - - - - +
+ + {{ 'device-profile.lwm2m.instances-list' | translate }} + + + {{instanceId}} + close + + + + + {{ 'device-profile.lwm2m.instances-input' | translate }} + + + + {{ translate.get('device-profile.lwm2m.valid-id-instance-no-min', { + instance: instanceId, min: instanceIdValueMin + }) | async }} + + + {{ translate.get('device-profile.lwm2m.valid-id-instance-no-max', { + instance: instanceId, max: instanceIdValueMax + }) | async }} + + + {{ translate.get('device-profile.lwm2m.instances-input-holder', { + instance: instanceId, max: instanceIdValueMax + }) | async }} + + +
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.scss b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.scss deleted file mode 100644 index 45e601db09..0000000000 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.scss +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Copyright © 2016-2020 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -:host ::ng-deep { - mat-form-field.lwm2m-instances-list { - & > .mat-form-field-wrapper > .mat-form-field-underline { - display: none; - } - } -} diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.ts index 6e09a6d254..1375b49112 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.ts @@ -14,35 +14,18 @@ /// limitations under the License. /// -import { - Component, - forwardRef, - Input, - OnInit, - ViewChild, - ElementRef, -} from '@angular/core'; -import { - ControlValueAccessor, - FormBuilder, - FormGroup, - NG_VALUE_ACCESSOR, Validators -} from '@angular/forms'; -import { coerceBooleanProperty } from '@angular/cdk/coercion'; +import { Component, forwardRef, } from '@angular/core'; +import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; -import { MatChipList } from '@angular/material/chips'; -import { - INSTANCES_ID_VALUE_MAX, - INSTANCES_ID_VALUE_MIN -} from './profile-config.models'; +import { INSTANCES_ID_VALUE_MAX, INSTANCES_ID_VALUE_MIN, KEY_REGEXP_NUMBER } from './profile-config.models'; import { TranslateService } from '@ngx-translate/core'; import { DeviceProfileService } from '@core/http/device-profile.service'; @Component({ selector: 'tb-profile-lwm2m-object-add-instances-list', templateUrl: './lwm2m-object-add-instances-list.component.html', - styleUrls: ['./lwm2m-object-add-instances-list.component.scss'], + styleUrls: [], providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => Lwm2mObjectAddInstancesListComponent), @@ -51,31 +34,13 @@ import { DeviceProfileService } from '@core/http/device-profile.service'; }) export class Lwm2mObjectAddInstancesListComponent implements ControlValueAccessor { - private requiredValue: boolean; - private disabled = false as boolean; - private dirty = false as boolean; + private disabled = false; + private dirty = false; - lwm2mObjectListFormGroup: FormGroup; - instancesIdsList: Set | null; - filteredObjectsList: Array; - instanceIdValueMin = INSTANCES_ID_VALUE_MIN as number; - instanceIdValueMax = INSTANCES_ID_VALUE_MAX as number; - - get required(): boolean { - return this.requiredValue; - } - - @Input() - set required(value: boolean) { - const newVal = coerceBooleanProperty(value); - if (this.requiredValue !== newVal) { - this.requiredValue = newVal; - this.updateValidators(); - } - } - - @ViewChild('instanceIdInput') instanceIdInput: ElementRef; - @ViewChild('chipList', {static: true}) chipList: MatChipList; + instancesListFormGroup: FormGroup; + instancesId = new Set(); + instanceIdValueMin = INSTANCES_ID_VALUE_MIN; + instanceIdValueMax = INSTANCES_ID_VALUE_MAX; private propagateChange = (v: any) => { }; @@ -83,19 +48,14 @@ export class Lwm2mObjectAddInstancesListComponent implements ControlValueAccesso public translate: TranslateService, private deviceProfileService: DeviceProfileService, private fb: FormBuilder) { - this.lwm2mObjectListFormGroup = this.fb.group({ - instancesIdsList: [null], - instanceIdInput: [null] + this.instancesListFormGroup = this.fb.group({ + instanceIdInput: [null, [ + Validators.min(this.instanceIdValueMin), + Validators.max(this.instanceIdValueMax), + Validators.pattern(KEY_REGEXP_NUMBER)]] }); } - private updateValidators = (): void => { - this.lwm2mObjectListFormGroup.get('instanceIdInput').setValidators([ - Validators.min(this.instanceIdValueMin), - Validators.max(this.instanceIdValueMax)]); - this.lwm2mObjectListFormGroup.get('instanceIdInput').updateValueAndValidity(); - } - registerOnChange(fn: any): void { this.propagateChange = fn; } @@ -106,68 +66,35 @@ export class Lwm2mObjectAddInstancesListComponent implements ControlValueAccesso setDisabledState(isDisabled: boolean): void { this.disabled = isDisabled; if (isDisabled) { - this.lwm2mObjectListFormGroup.disable({emitEvent: false}); + this.instancesListFormGroup.disable({emitEvent: false}); } else { - this.lwm2mObjectListFormGroup.enable({emitEvent: false}); + this.instancesListFormGroup.enable({emitEvent: false}); } } writeValue(value: Set): void { - this.instancesIdsList = new Set(); if (value && value.size) { - value.forEach(item => this.instancesIdsList.add(item)); - this.lwm2mObjectListFormGroup.get('instancesIdsList').setValue(this.instancesIdsList); + this.instancesId = value; } - this.updateValidators(); this.dirty = false; } - add = (value: number): void => { - if (!isNaN(value) && this.lwm2mObjectListFormGroup.get('instanceIdInput').valid) { - this.instancesIdsList.add(value); - this.lwm2mObjectListFormGroup.get('instancesIdsList').setValue(this.instancesIdsList); - this.propagateChange(this.instancesIdsList); + add = (): void => { + if (this.instancesListFormGroup.get('instanceIdInput').valid) { + this.instancesId.add(this.instanceId); + this.instancesListFormGroup.get('instanceIdInput').setValue(null); + this.propagateChange(this.instancesId); this.dirty = true; } - this.clear(); } remove = (object: number): void => { - this.instancesIdsList.delete(object); - this.lwm2mObjectListFormGroup.get('instancesIdsList').setValue(this.instancesIdsList); - this.propagateChange(this.instancesIdsList); + this.instancesId.delete(object); + this.propagateChange(this.instancesId); this.dirty = true; - this.clear(); - } - // - // displayFn(object?: number): number | undefined { - // return object ? object : undefined; - // } - - private clear = (): void => { - this.lwm2mObjectListFormGroup.get('instanceIdInput').patchValue(null, {emitEvent: true}); - this.instanceIdInput.nativeElement.value = ''; - setTimeout(() => { - this.instanceIdInput.nativeElement.blur(); - this.instanceIdInput.nativeElement.focus(); - }, 0); } - onkeydown = (e: KeyboardEvent): boolean => { - if (e.keyCode === 189 || e.keyCode === 187 || e.keyCode === 109 || e.keyCode === 107) { - return false; - } else if (e.keyCode === 8) { - if (this.lwm2mObjectListFormGroup.get('instanceIdInput').value == null) { - this.clear(); - } - this.instanceIdInput.nativeElement.focus(); - } - } - - onFocus = (): void => { - if (this.dirty) { - this.lwm2mObjectListFormGroup.get('instanceIdInput').updateValueAndValidity({onlySelf: true, emitEvent: true}); - this.dirty = false; - } + get instanceId(): number { + return this.instancesListFormGroup.get('instanceIdInput').value; } } diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.html index 6c7706071f..303e38f180 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.html @@ -30,11 +30,9 @@
-
- - -
+ +
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.html index 7ad661752b..260f0016f5 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.html @@ -16,7 +16,7 @@ --> - + - + {{ 'device-profile.lwm2m.object-list-empty' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts index f5a84638ed..d0f6c3cc47 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts @@ -19,8 +19,6 @@ import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Valida import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; -import { MatChipList } from '@angular/material/chips'; -import { MatAutocomplete } from '@angular/material/autocomplete'; import { Observable } from 'rxjs'; import { filter, map, mergeMap, share, tap } from 'rxjs/operators'; import { ObjectLwM2M } from './profile-config.models'; @@ -43,9 +41,9 @@ import { Direction } from '@shared/models/page/sort-order'; export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, Validators { private requiredValue: boolean; - private dirty = false as boolean; + private dirty = false; - lwm2mObjectListFormGroup: FormGroup; + lwm2mListFormGroup: FormGroup; modelValue: Array | null; objectsList: Array = []; filteredObjectsList: Observable>; @@ -72,8 +70,6 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V removeList = new EventEmitter(); @ViewChild('objectInput') objectInput: ElementRef; - @ViewChild('objectAutocomplete') matAutocomplete: MatAutocomplete; - @ViewChild('chipList', {static: true}) chipList: MatChipList; private propagateChange = (v: any) => { }; @@ -81,15 +77,15 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V public translate: TranslateService, private deviceProfileService: DeviceProfileService, private fb: FormBuilder) { - this.lwm2mObjectListFormGroup = this.fb.group({ + this.lwm2mListFormGroup = this.fb.group({ objectsList: [this.objectsList], objectLwm2m: [null, this.required ? [Validators.required] : []] }); } private updateValidators = (): void => { - this.lwm2mObjectListFormGroup.get('objectLwm2m').setValidators(this.required ? [Validators.required] : []); - this.lwm2mObjectListFormGroup.get('objectLwm2m').updateValueAndValidity(); + this.lwm2mListFormGroup.get('objectLwm2m').setValidators(this.required ? [Validators.required] : []); + this.lwm2mListFormGroup.get('objectLwm2m').updateValueAndValidity(); } registerOnChange(fn: any): void { @@ -100,7 +96,7 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V } ngOnInit() { - this.filteredObjectsList = this.lwm2mObjectListFormGroup.get('objectLwm2m').valueChanges + this.filteredObjectsList = this.lwm2mListFormGroup.get('objectLwm2m').valueChanges .pipe( tap((value) => { if (value && typeof value !== 'string') { @@ -110,21 +106,17 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V } }), filter((value) => typeof value === 'string'), - map((value) => value ? (typeof value === 'string' ? value : value.name) : ''), mergeMap(name => this.fetchListObjects(name)), share() ); } - ngAfterViewInit = (): void => { - } - setDisabledState(isDisabled: boolean): void { this.disabled = isDisabled; if (isDisabled) { - this.lwm2mObjectListFormGroup.disable({emitEvent: false}); + this.lwm2mListFormGroup.disable({emitEvent: false}); } else { - this.lwm2mObjectListFormGroup.enable({emitEvent: false}); + this.lwm2mListFormGroup.enable({emitEvent: false}); } } @@ -134,35 +126,22 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V if (value.hasOwnProperty(objectIds) && value[objectIds] != null && value[objectIds].length > 0) { this.modelValue = [...value[objectIds]]; this.objectsList = value.objectsList; - this.lwm2mObjectListFormGroup.get('objectsList').setValue(this.objectsList); } else { this.objectsList = []; - this.lwm2mObjectListFormGroup.get('objectsList').setValue(this.objectsList); this.modelValue = null; } + this.lwm2mListFormGroup.get('objectsList').setValue(this.objectsList); this.dirty = true; } - // reset() { - // this.objectsList = []; - // this.lwm2mObjectListFormGroup.get('objectsList').setValue(this.objectsList); - // this.modelValue = null; - // if (this.objectInput) { - // this.objectInput.nativeElement.value = ''; - // } - // this.lwm2mObjectListFormGroup.get('objectLwm2m').patchValue('', {emitEvent: false}); - // this.propagateChange(this.modelValue); - // this.dirty = true; - // } - - private add = (object: ObjectLwM2M): void => { + private add(object: ObjectLwM2M): void { if (!this.modelValue || this.modelValue.indexOf(object.id) === -1) { if (!this.modelValue) { this.modelValue = []; } this.modelValue.push(object.id); this.objectsList.push(object); - this.lwm2mObjectListFormGroup.get('objectsList').setValue(this.objectsList); + this.lwm2mListFormGroup.get('objectsList').setValue(this.objectsList); this.addList.next(this.objectsList); } this.propagateChange(this.modelValue); @@ -173,7 +152,7 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V let index = this.objectsList.indexOf(object); if (index >= 0) { this.objectsList.splice(index, 1); - this.lwm2mObjectListFormGroup.get('objectsList').setValue(this.objectsList); + this.lwm2mListFormGroup.get('objectsList').setValue(this.objectsList); index = this.modelValue.indexOf(object.id); this.modelValue.splice(index, 1); this.removeList.next(object); @@ -189,9 +168,11 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V return object ? object.name : undefined; } + // @TODO: add support page size + // @TODO: filter for id + name private fetchListObjects = (searchText?: string): Observable> => { this.searchText = searchText; - const pageLink = new PageLink(10, 0, searchText, { + const pageLink = new PageLink(50, 0, searchText, { property: 'name', direction: Direction.ASC }); @@ -202,14 +183,14 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V onFocus = (): void => { if (this.dirty) { - this.lwm2mObjectListFormGroup.get('objectLwm2m').updateValueAndValidity({onlySelf: true, emitEvent: true}); + this.lwm2mListFormGroup.get('objectLwm2m').updateValueAndValidity({onlySelf: true, emitEvent: true}); this.dirty = false; } } private clear = (value: string = ''): void => { this.objectInput.nativeElement.value = value; - this.lwm2mObjectListFormGroup.get('objectLwm2m').patchValue(value, {emitEvent: true}); + this.lwm2mListFormGroup.get('objectLwm2m').patchValue(value, {emitEvent: true}); setTimeout(() => { this.objectInput.nativeElement.blur(); this.objectInput.nativeElement.focus(); diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts index 11ffdf0fe5..f6a600ae99 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts @@ -171,7 +171,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor } private updateValidators = (): void => { - this.observeAttrTelemetryFormGroup.get('clientLwM2M').setValidators(this.required ? [Validators.required] : []); + this.observeAttrTelemetryFormGroup.get('clientLwM2M').setValidators(this.required ? Validators.required : []); this.observeAttrTelemetryFormGroup.get('clientLwM2M').updateValueAndValidity(); } @@ -188,7 +188,6 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor return false; } - getChecked = (instance: AbstractControl, type: string): boolean => { const resources = instance.get('resources').value as ResourceLwM2M[]; return isDefinedAndNotNull(resources) && resources.every(resource => resource[type]); @@ -221,15 +220,11 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor $event.stopPropagation(); $event.preventDefault(); } - const instancesIds = new Set(); - object.instances.forEach(inst => { - instancesIds.add(inst.id); - }); this.dialog.open(Lwm2mObjectAddInstancesComponent, { disableClose: true, panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], data: { - instancesIds: this.setInstancesIds(object.instances), + instancesIds: this.instancesToSetId(object.instances), objectName: object.name, objectId: object.id } @@ -243,21 +238,15 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor } private updateInstancesIds = (data: Lwm2mObjectAddInstancesData): void => { - const valueNew = new Set(); - const valueOld = new Set(); - data.instancesIds.forEach(value => { - valueNew.add(value); - }); - const oldInstances = (this.observeAttrTelemetryFormGroup.get('clientLwM2M').value as ObjectLwM2M []) - .find(e => e.id === data.objectId).instances; - oldInstances.forEach(inst => { - valueOld.add(inst.id); - }); - if (!isEqual(valueOld, valueNew)) { - const idsDel = this.diffBetweenSet(valueOld, valueNew); - const idsAdd = this.diffBetweenSet(valueNew, valueOld); + const instances = (this.observeAttrTelemetryFormGroup.get('clientLwM2M').value as ObjectLwM2M[]) + .find(objectLwM2M => objectLwM2M.id === data.objectId).instances; + const valueOld = this.instancesToSetId(instances); + + if (!isEqual(valueOld, data.instancesIds)) { + const idsDel = this.diffBetweenSet(valueOld, data.instancesIds); + const idsAdd = this.diffBetweenSet(data.instancesIds, valueOld); if (idsAdd.size) { - this.addInstancesNew(data.objectId, idsAdd); + this.addInstancesNew(data.objectId, idsAdd, instances.find(instance => instance.id === 0)); } if (idsDel.size) { this.deleteInstances(data.objectId, idsDel); @@ -276,13 +265,11 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor }); } - private addInstancesNew = (objectId: number, idsAdd: Set): void => { - const instancesValue = (this.observeAttrTelemetryFormGroup.get('clientLwM2M').value as ObjectLwM2M []) - .find(objectLwM2M => objectLwM2M.id === objectId).instances; + private addInstancesNew = (objectId: number, idsAdd: Set, instance: Instance): void => { const instancesFormArray = ((this.observeAttrTelemetryFormGroup.get('clientLwM2M') as FormArray).controls .find(e => e.value.id === objectId).get('instances') as FormArray) as FormArray; idsAdd.forEach(x => { - const instanceNew = deepClone(instancesValue[0]) as Instance; + const instanceNew = deepClone(instance); instanceNew.resources.forEach(r => { r.attribute = false; r.telemetry = false; @@ -296,17 +283,11 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor (instancesFormArray.controls as FormGroup[]).sort((a, b) => a.value.id - b.value.id); } - private diffBetweenSet = (firstSet: Set, secondSet: Set): Set => { + private diffBetweenSet(firstSet: Set, secondSet: Set): Set { return new Set([...Array.from(firstSet)].filter(x => !secondSet.has(x))); } - private setInstancesIds = (instances: Instance []): Set => { - const instancesIds = new Set(); - if (instances && instances.length) { - instances.forEach(inst => { - instancesIds.add(inst.id); - }); - } - return instancesIds; + private instancesToSetId = (instances: Instance[]): Set => { + return new Set(instances.map(x => x.id)); } } diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/profile-config.models.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/profile-config.models.ts index 681e2fa295..1849fd3279 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/profile-config.models.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/profile-config.models.ts @@ -33,6 +33,7 @@ export const DEFAULT_BOOTSTRAP_SERVER_ACCOUNT_TIME_OUT = 0; export const LEN_MAX_PUBLIC_KEY_RPK = 182; export const LEN_MAX_PUBLIC_KEY_X509 = 3000; export const KEY_REGEXP_HEX_DEC = /^[-+]?[0-9A-Fa-f]+\.?[0-9A-Fa-f]*?$/; +export const KEY_REGEXP_NUMBER = /^\d*$/; export const INSTANCES_ID_VALUE_MIN = 0; export const INSTANCES_ID_VALUE_MAX = 65535; From e6d4e91e25a529afedd16b5b102684f318c75f8d Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 20 Jan 2021 19:17:13 +0200 Subject: [PATCH 051/249] Lwm2m: front: refactoring n number validators --- .../server/LwM2MTransportServiceImpl.java | 59 ++++++++++--------- .../lwm2m/server/client/LwM2MClient.java | 2 +- ...m-object-add-instances-list.component.html | 16 +++-- ...m2m-object-add-instances-list.component.ts | 4 +- .../device/lwm2m/profile-config.models.ts | 2 +- .../assets/locale/locale.constant-en_US.json | 1 + 6 files changed, 42 insertions(+), 42 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServiceImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServiceImpl.java index 072c7bc402..3255d24760 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServiceImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServiceImpl.java @@ -20,6 +20,7 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.Link; import org.eclipse.leshan.core.model.ResourceModel; import org.eclipse.leshan.core.node.LwM2mMultipleResource; import org.eclipse.leshan.core.node.LwM2mObject; @@ -153,7 +154,7 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { lwM2MClient.setLwM2MTransportServiceImpl(this); lwM2MClient.setSessionUuid(UUID.randomUUID()); this.sentLogsToThingsboard(LOG_LW2M_INFO + ": Client Registered", registration); -// this.setLwM2MClient(lwServer, registration, lwM2MClient); +// this.setLwM2mFromClientValue(lwServer, registration, lwM2MClient); SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration); if (sessionInfo != null) { lwM2MClient.setDeviceUuid(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB())); @@ -164,6 +165,7 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN), null); transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), null); this.sentLogsToThingsboard(LOG_LW2M_INFO + ": Client create after Registration", registration); + this.putDelayedUpdateResourcesThingsboard(lwM2MClient); } else { log.error("Client: [{}] onRegistered [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); } @@ -198,7 +200,6 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { }); } - /** * @param registration - Registration LwM2M Client * @param observations - All paths observations before unReg @@ -279,33 +280,33 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { * @param registration - Registration LwM2M Client * @param lwM2MClient - object with All parameters off client */ - private void setLwM2MClient(LeshanServer lwServer, Registration registration, LwM2MClient lwM2MClient) { -// Arrays.stream(registration.getObjectLinks()).forEach(url -> { -// LwM2mPath pathIds = new LwM2mPath(url.getUrl()); -// if (pathIds.isObjectInstance() && !pathIds.isResource()) { -// // #1 -// lwM2MClient.getPendingRequests().add(url.getUrl()); -// // #2 -// lwM2MTransportRequest.sendAllRequest(lwServer, registration, url.getUrl(), GET_TYPE_OPER_READ, ContentFormat.TLV.getName(), -// lwM2MClient, null, null, this.context.getCtxServer().getTimeout(), false); -// } -// }); - -// // #1 -// for (Link url : registration.getObjectLinks()) { -// LwM2mPath pathIds = new LwM2mPath(url.getUrl()); -// if (pathIds.isObjectInstance() && !pathIds.isResource()) { -// lwM2MClient.getPendingRequests().add(url.getUrl()); -// } -// } -// // #2 -// for (Link url : registration.getObjectLinks()) { -// LwM2mPath pathIds = new LwM2mPath(url.getUrl()); -// if (pathIds.isObjectInstance() && !pathIds.isResource()) { -// lwM2MTransportRequest.sendAllRequest(lwServer, registration, url.getUrl(), GET_TYPE_OPER_READ, ContentFormat.TLV.getName(), -// lwM2MClient, null, null, this.context.getCtxServer().getTimeout(), false); -// } -// } + private void setLwM2mFromClientValue(LeshanServer lwServer, Registration registration, LwM2MClient lwM2MClient) { + Arrays.stream(registration.getObjectLinks()).forEach(url -> { + LwM2mPath pathIds = new LwM2mPath(url.getUrl()); + if (pathIds.isObjectInstance() && !pathIds.isResource()) { + // #1 + lwM2MClient.getPendingRequests().add(url.getUrl()); + // #2 + lwM2MTransportRequest.sendAllRequest(lwServer, registration, url.getUrl(), GET_TYPE_OPER_READ, ContentFormat.TLV.getName(), + lwM2MClient, null, null, this.context.getCtxServer().getTimeout(), false); + } + }); + + // #1 + for (Link url : registration.getObjectLinks()) { + LwM2mPath pathIds = new LwM2mPath(url.getUrl()); + if (pathIds.isObjectInstance() && !pathIds.isResource()) { + lwM2MClient.getPendingRequests().add(url.getUrl()); + } + } + // #2 + for (Link url : registration.getObjectLinks()) { + LwM2mPath pathIds = new LwM2mPath(url.getUrl()); + if (pathIds.isObjectInstance() && !pathIds.isResource()) { + lwM2MTransportRequest.sendAllRequest(lwServer, registration, url.getUrl(), GET_TYPE_OPER_READ, ContentFormat.TLV.getName(), + lwM2MClient, null, null, this.context.getCtxServer().getTimeout(), false); + } + } // #1 Arrays.stream(registration.getObjectLinks()).forEach(url -> { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java index fdb2055500..f20853299d 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java @@ -93,7 +93,7 @@ public class LwM2MClient implements Cloneable { this.pendingRequests.remove(path); if (this.pendingRequests.size() == 0) { this.initValue(); - this.lwM2MTransportServiceImpl.putDelayedUpdateResourcesThingsboard(this); +// this.lwM2MTransportServiceImpl.putDelayedUpdateResourcesThingsboard(this); } } diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.html index 5a03f3f54d..34d77c299b 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.html @@ -31,9 +31,7 @@ {{ 'device-profile.lwm2m.instances-input' | translate }} - - {{ translate.get('device-profile.lwm2m.valid-id-instance-no-min', { - instance: instanceId, min: instanceIdValueMin + {{ translate.get('device-profile.lwm2m.valid-id-instance', { + count: 2, instance: instanceId, min: instanceIdValueMin }) | async }} - {{ translate.get('device-profile.lwm2m.valid-id-instance-no-max', { - instance: instanceId, max: instanceIdValueMax + {{ translate.get('device-profile.lwm2m.valid-id-instance', { + count: 1, instance: instanceId, max: instanceIdValueMax }) | async }} - {{ translate.get('device-profile.lwm2m.instances-input-holder', { - instance: instanceId, max: instanceIdValueMax + {{ translate.get('device-profile.lwm2m.valid-id-instance', { + count: 0, instance: instanceId, max: instanceIdValueMax }) | async }} diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.ts index 1375b49112..1921db396d 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.ts @@ -80,8 +80,8 @@ export class Lwm2mObjectAddInstancesListComponent implements ControlValueAccesso } add = (): void => { - if (this.instancesListFormGroup.get('instanceIdInput').valid) { - this.instancesId.add(this.instanceId); + if (this.instancesListFormGroup.get('instanceIdInput').valid && Number.isFinite(Number(this.instanceId))) { + this.instancesId.add(Number(this.instanceId)); this.instancesListFormGroup.get('instanceIdInput').setValue(null); this.propagateChange(this.instancesId); this.dirty = true; diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/profile-config.models.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/profile-config.models.ts index 1849fd3279..11c16ac802 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/profile-config.models.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/profile-config.models.ts @@ -33,7 +33,7 @@ export const DEFAULT_BOOTSTRAP_SERVER_ACCOUNT_TIME_OUT = 0; export const LEN_MAX_PUBLIC_KEY_RPK = 182; export const LEN_MAX_PUBLIC_KEY_X509 = 3000; export const KEY_REGEXP_HEX_DEC = /^[-+]?[0-9A-Fa-f]+\.?[0-9A-Fa-f]*?$/; -export const KEY_REGEXP_NUMBER = /^\d*$/; +export const KEY_REGEXP_NUMBER = /^(\-?|\+?)\d*$/; export const INSTANCES_ID_VALUE_MIN = 0; export const INSTANCES_ID_VALUE_MAX = 65535; diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 1ff1e0a6e0..b26fb40b1e 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -1102,6 +1102,7 @@ "no-objects-matching": "No objects matching '{{object}}' were found.", "valid-id-instance-no-min": "Instance number '{{instance}}' no validated. Min value='{{min}}'", "valid-id-instance-no-max": "Instance number '{{instance}}' no validated. Max value='{{max}}'", + "valid-id-instance": "Instance number '{{instance}}' no validated. { count, plural, 1 {Max value='{{max}}'} 2 {Min value='{{min}}'} other {Must be only number} }", "model-tab": "LWM2M Model", "add-instances-tip": "Add new instances", "instances-list": "Instances list", From 758ce9f03e64cb94b05a328008cf21f1bea82fd5 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Wed, 20 Jan 2021 19:19:47 +0200 Subject: [PATCH 052/249] UI: Fixed bug trip animation widget after change speed or change time to the time slider --- .../history-selector.component.html | 6 +- .../history-selector.component.ts | 56 +++++++++---------- 2 files changed, 30 insertions(+), 32 deletions(-) diff --git a/ui-ngx/src/app/shared/components/time/history-selector/history-selector.component.html b/ui-ngx/src/app/shared/components/time/history-selector/history-selector.component.html index 4261dec207..4782283d49 100644 --- a/ui-ngx/src/app/shared/components/time/history-selector/history-selector.component.html +++ b/ui-ngx/src/app/shared/components/time/history-selector/history-selector.component.html @@ -24,7 +24,7 @@ skip_previous
- +
{{ this.currentTime | date:'medium'}} @@ -47,8 +47,8 @@ pause_circle_outline - + {{speedValue}}
-
\ No newline at end of file +
diff --git a/ui-ngx/src/app/shared/components/time/history-selector/history-selector.component.ts b/ui-ngx/src/app/shared/components/time/history-selector/history-selector.component.ts index 7cdcc42eec..c5bc1d61c3 100644 --- a/ui-ngx/src/app/shared/components/time/history-selector/history-selector.component.ts +++ b/ui-ngx/src/app/shared/components/time/history-selector/history-selector.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core'; +import { ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, Output } from '@angular/core'; import { interval } from 'rxjs'; import { filter } from 'rxjs/operators'; import { HistorySelectSettings } from '@app/modules/home/components/widget/lib/maps/map-models'; @@ -24,9 +24,9 @@ import { HistorySelectSettings } from '@app/modules/home/components/widget/lib/m templateUrl: './history-selector.component.html', styleUrls: ['./history-selector.component.scss'] }) -export class HistorySelectorComponent implements OnInit, OnChanges { +export class HistorySelectorComponent implements OnChanges { - @Input() settings: HistorySelectSettings + @Input() settings: HistorySelectSettings; @Input() minTime: number; @Input() maxTime: number; @Input() step = 1000; @@ -47,9 +47,6 @@ export class HistorySelectorComponent implements OnInit, OnChanges { constructor(private cd: ChangeDetectorRef) { } - ngOnInit(): void { - } - ngOnChanges() { this.maxTimeIndex = Math.ceil((this.maxTime - this.minTime) / this.step); this.currentTime = this.minTime === Infinity ? null : this.minTime; @@ -57,34 +54,34 @@ export class HistorySelectorComponent implements OnInit, OnChanges { play() { this.playing = true; - if (!this.interval) + if (!this.interval) { this.interval = interval(1000 / this.speed) .pipe( - filter(() => this.playing)).subscribe(() => { - this.index++; - this.currentTime = this.minTime + this.index * this.step; - if (this.index <= this.maxTimeIndex) { - this.cd.detectChanges(); - this.timeUpdated.emit(this.currentTime); - } - else { - this.interval.complete(); - } - }, err => { - console.error(err); - }, () => { - this.currentTime = this.index = this.minTimeIndex; + filter(() => this.playing) + ).subscribe(() => { + this.index++; + this.currentTime = this.minTime + this.index * this.step; + if (this.index <= this.maxTimeIndex) { + this.cd.detectChanges(); + this.timeUpdated.emit(this.currentTime); + } else { this.playing = false; - this.interval = null; + this.interval.complete(); this.cd.detectChanges(); - }); + } + }, err => { + console.error(err); + }, () => { + this.interval = null; + }); + } } - reeneble() { - if (this.playing) { - const position = this.index; + reInit() { + if (this.interval) { this.interval.complete(); - this.index = position; + } + if (this.playing) { this.play(); } } @@ -138,8 +135,9 @@ export class HistorySelectorComponent implements OnInit, OnChanges { this.pause(); } - changeIndex() { - this.currentTime = this.minTime + this.index * this.step; + changeIndex(index: number) { + this.index = index; + this.currentTime = this.minTime + index * this.step; this.timeUpdated.emit(this.currentTime); } } From 03b5ca3571ca380e54f6af15dea857d85202b24d Mon Sep 17 00:00:00 2001 From: lsyer Date: Thu, 21 Jan 2021 11:05:27 +0800 Subject: [PATCH 053/249] Update some translations: locale.constant-zh_CN.json --- .../assets/locale/locale.constant-zh_CN.json | 328 +++++++++--------- 1 file changed, 164 insertions(+), 164 deletions(-) diff --git a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json index 12f0024529..7c95423f80 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json @@ -73,9 +73,9 @@ "enable-proxy": "启用代理", "enable-tls": "启用TLS", "error-verification-url": "域名不应包含符号 “/” 和 “:”。例:thingsboard.io", - "general": "总则", - "general-policy": "General policy", - "general-settings": "常规设置", + "general": "基本设置", + "general-policy": "基本策略", + "general-settings": "基本设置", "mail-from": "邮件来自", "mail-from-required": "邮件发件人必填。", "max-failed-login-attempts": "登录失败之前的最大登录尝试次数", @@ -91,7 +91,7 @@ "minimum-special-characters-range": "特殊字符的最小数目不能为负数", "minimum-uppercase-letters": "最小大写字母数", "minimum-uppercase-letters-range": "大写字母的最小数目不能为负数", - "number-from": "来自的电话号码", + "number-from": "发送方电话号码", "number-from-required": "发送方电话号码必填。", "number-to": "电话号码至", "number-to-required": "电话号码必填。", @@ -182,11 +182,11 @@ "sms-message": "短信", "sms-message-max-length": "短信长度不能超过1600个字符", "sms-message-required": "短消息内容必填。", - "sms-provider": "SMS provider", - "sms-provider-settings": "SMS provider 设置", - "sms-provider-type": "SMS provider 类型", + "sms-provider": "SMS 服务商", + "sms-provider-settings": "SMS 服务商设置", + "sms-provider-type": "SMS 服务商类型", "sms-provider-type-aws-sns": "亚马逊社交网站", - "sms-provider-type-required": "SMS provider 类型必填。", + "sms-provider-type-required": "SMS 服务商类型必填。", "sms-provider-type-twilio": "Twilio", "smtp-host": "SMTP主机", "smtp-host-required": "SMTP主机必填。", @@ -224,15 +224,15 @@ "acknowledge": "应答", "aknowledge-alarm-text": "确定要确认报警吗?", "aknowledge-alarm-title": "确认报警", - "aknowledge-alarms-text": "确定要确认 { count, plural, 1 {1 个警告} other {# 个警告} }?", - "aknowledge-alarms-title": "确认 { count, plural, 1 {1 个警告} other {# 个警告} }", + "aknowledge-alarms-text": "确定要确认 { count, plural, 1 {# 个警告} other {# 个警告} }?", + "aknowledge-alarms-title": "确认 { count, plural, 1 {# 个警告} other {# 个警告} }", "alarm": "警告", "alarm-details": "报警详细信息", - "alarm-filter": "报警过滤器", + "alarm-filter": "报警筛选器", "alarm-required": "警告必填", "alarm-severity-list": "警报严重性列表", "alarm-status": "警告状态", - "alarm-status-filter": "报警状态过滤器", + "alarm-status-filter": "报警状态筛选器", "alarm-status-list": "报警状态列表", "alarm-type-list": "报警类型列表", "alarms": "警告", @@ -242,11 +242,11 @@ "clear": "清除", "clear-alarm-text": "确定要清除警报吗?", "clear-alarm-title": "清除警报", - "clear-alarms-text": "确定要清除 { count, plural, 1 {1 个警告} other {# 个警告} }?", - "clear-alarms-title": "清除 { count, plural, 1 {1 个警告} other {# 个警告} }", + "clear-alarms-text": "确定要清除 { count, plural, 1 {# 个警告} other {# 个警告} }?", + "clear-alarms-title": "清除 { count, plural, 1 {# 个警告} other {# 个警告} }", "clear-time": "清除时间", "created-time": "创建时间", - "details": "细节", + "details": "详情", "display-status": { "ACTIVE_ACK": "Active 已确认", "ACTIVE_UNACK": "Active 未确认", @@ -268,7 +268,7 @@ "originator-type": "Originator 类型", "polling-interval": "警告轮询间隔(秒)", "polling-interval-required": "警告轮询间隔必填。", - "search": "搜索警告", + "search": "查找警告", "search-propagated-alarms": "检索已传递的警报", "search-status": { "ACK": "已确认", @@ -278,7 +278,7 @@ "UNACK": "未确认" }, "select-alarm": "选择警告", - "selected-alarms": "已选择 { count, plural, 1 {1 个警告} other {# 个警告} }", + "selected-alarms": "已选择 { count, plural, 1 {# 个警告} other {# 个警告} }", "severity": "严重程度", "severity-critical": "危险", "severity-indeterminate": "不确定", @@ -297,9 +297,9 @@ "default-state-entity": "默认状态实体", "duplicate-alias": "别名已经存在。", "edit": "编辑别名", - "entity-filter": "实体过滤", - "entity-filter-no-entity-matched": "未找到符合指定过滤条件的实体。", - "filter-type": "过滤类型", + "entity-filter": "实体筛选器", + "entity-filter-no-entity-matched": "未找到符合指定筛选条件的实体。", + "filter-type": "筛选器类型", "filter-type-apiUsageState": "Api使用状态", "filter-type-asset-search-query": "资产搜索查询", "filter-type-asset-search-query-description": "类型为 {{assetTypes}} 且具有 {{relationType}} 关联 {{direction}} {{rootEntity}} 的资产", @@ -320,15 +320,15 @@ "filter-type-entity-view-type-description": "类型为 '{{entityView}}' 的实体视图", "filter-type-relations-query": "关联查询", "filter-type-relations-query-description": "具有 {{relationType}} 关联 {{direction}} {{rootEntity}} 的 {{entities}} ", - "filter-type-required": "过滤类型必填。", + "filter-type-required": "筛选器类型必填。", "filter-type-single-entity": "单个实体", - "filter-type-state-entity": "实体(仪表板状态)", - "filter-type-state-entity-description": "实体令牌(仪表板状态参数)", + "filter-type-state-entity": "仪表板实体状态", + "filter-type-state-entity-description": "仪表板实体令牌状态参数", "last-level-relation": "仅获取最后一级关联", "max-relation-level": "最大关联层级", "name": "别名", "name-required": "别名必填", - "no-entity-filter-specified": "没有指定实体过滤条件", + "no-entity-filter-specified": "没有指定实体筛选器", "resolve-multiple": "解决为多实体", "root-entity": "根实体", "root-state-entity": "使用仪表板状态实体作为根实体", @@ -354,7 +354,7 @@ "javascript-functions-hourly-activity": "JavaScript functions hourly activity", "javascript-functions-monthly-activity": "JavaScript functions monthly activity", "latest-error": "最新错误", - "messages": "信息", + "messages": "消息", "permanent-failures": "${entityName} 永久性故障", "permanent-timeouts": "${entityName} 永久超时", "processing-failures": "${entityName} 处理失败", @@ -381,11 +381,11 @@ "telemetry-persistence-hourly-activity": "Telemetry persistence hourly activity", "telemetry-persistence-monthly-activity": "Telemetry persistence monthly activity", "transport": "Transport", - "transport-daily-activity": "运输日常活动", + "transport-daily-activity": "Transport daily activity", "transport-data-points": "传输数据点", "transport-hourly-activity": "Transport hourly activity", "transport-messages": "传输消息", - "transport-monthly-activity": "运输月度活动", + "transport-monthly-activity": "Transport monthly activity", "view-details": "查看详细信息", "view-statistics": "查看统计信息" }, @@ -406,7 +406,7 @@ "assign-asset-to-customer": "将资产分配给客户", "assign-asset-to-customer-text": "请选择要分配给客户的资产", "assign-assets": "分配资产", - "assign-assets-text": "分配 { count, plural, 1 {1 个资产} other {# 个资产} } 给客户", + "assign-assets-text": "分配 { count, plural, 1 {# 个资产} other {# 个资产} } 给客户", "assign-new-asset": "分配新资产", "assign-to-customer": "分配给客户", "assign-to-customer-text": "请选择客户以分配资产", @@ -416,11 +416,11 @@ "delete-asset-text": "小心!确认后资产及其所有相关数据将不可恢复。", "delete-asset-title": "确定要删除资产 '{{assetName}}'?", "delete-assets": "删除资产", - "delete-assets-action-title": "删除 { count, plural, 1 {1 个资产} other {# 个资产} }", + "delete-assets-action-title": "删除 { count, plural, 1 {# 个资产} other {# 个资产} }", "delete-assets-text": "请注意:确认后,所有选定的资产将被删除,所有相关的数据将变得不可恢复。", - "delete-assets-title": "确定要删除 { count, plural, 1 {1 个资产} other {# 个资产} }?", + "delete-assets-title": "确定要删除 { count, plural, 1 {# 个资产} other {# 个资产} }?", "description": "说明", - "details": "细节", + "details": "详情", "enter-asset-type": "输入资产类型", "events": "事件", "idCopiedMessage": "资产ID已经复制到粘贴板", @@ -440,19 +440,19 @@ "no-assets-matching": "没有找到匹配 '{{entity}}' 的资产。", "no-assets-text": "未找到资产", "public": "公开", - "search": "搜索资产", + "search": "查找资产", "select-asset": "选择资产", "select-asset-type": "选择资产类型", - "selected-assets": "已选择 { count, plural, 1 {1 个资产} other {# 个资产} }", + "selected-assets": "已选择 { count, plural, 1 {# 个资产} other {# 个资产} }", "type": "类型", "type-required": "类型必填。", "unassign-asset": "未分配资产", "unassign-asset-text": "确认后,资产将未分配,客户无法访问。", "unassign-asset-title": "您确定要取消对'{{assetName}}'资产的分配吗?", "unassign-assets": "取消分配资产", - "unassign-assets-action-title": "从客户处取消分配 { count, plural, 1 {1 个资产} other {# 个资产} }", + "unassign-assets-action-title": "从客户处取消分配 { count, plural, 1 {# 个资产} other {# 个资产} }", "unassign-assets-text": "确认后,所有选定的资产将被分配,客户无法访问。", - "unassign-assets-title": "您确定要取消分配 { count, plural, 1 {1 个资产} other {# 个资产} }吗?", + "unassign-assets-title": "您确定要取消分配 { count, plural, 1 {# 个资产} other {# 个资产} }吗?", "unassign-from-customer": "取消分配客户", "view-assets": "查看资产" }, @@ -464,7 +464,7 @@ "attributes-scope": "设备属性范围", "delete-attributes": "删除属性", "delete-attributes-text": "注意,确认后所有选中的属性都会被删除。", - "delete-attributes-title": "您确定要删除 { count, plural, 1 {1 个属性} other {# 个属性} }吗?", + "delete-attributes-title": "您确定要删除 { count, plural, 1 {# 个属性} other {# 个属性} }吗?", "enter-attribute-value": "输入属性值", "key": "键名", "key-required": "属性键必填。", @@ -478,8 +478,8 @@ "scope-latest-telemetry": "最新遥测数据", "scope-server": "服务端属性", "scope-shared": "共享属性", - "selected-attributes": "已选择{ count, plural, 1 {1 个属性} other {# 个属性} }", - "selected-telemetry": "已选择 { count, plural, 1 {1 telemetry unit} other {# telemetry units} }", + "selected-attributes": "已选择{ count, plural, 1 {# 个属性} other {# 个属性} }", + "selected-telemetry": "已选择 { count, plural, 1 {# telemetry unit} other {# telemetry units} }", "show-on-widget": "在部件上显示", "value": "价值", "value-required": "属性值必填。", @@ -491,7 +491,7 @@ "audit-log-details": "审计日志详情", "audit-logs": "审计日志", "clear-search": "清空查找", - "details": "细节", + "details": "详情", "entity-name": "实体名称", "entity-type": "实体类型", "failure-details": "失败详情", @@ -591,11 +591,11 @@ "delete": "删除此客户", "delete-customer-text": "小心!确认后,客户及其所有相关数据将不可恢复。", "delete-customer-title": "您确定要删除客户'{{customerTitle}}'吗?", - "delete-customers-action-title": "删除 { count, plural, 1 {1 个客户} other {# 个客户} }", + "delete-customers-action-title": "删除 { count, plural, 1 {# 个客户} other {# 个客户} }", "delete-customers-text": "小心!确认后,所有选定的客户将被删除,所有相关数据将不可恢复。", - "delete-customers-title": "您确定要删除 { count, plural, 1 {1 个客户} other {# 个客户} }吗?", + "delete-customers-title": "您确定要删除 { count, plural, 1 {# 个客户} other {# 个客户} }吗?", "description": "说明", - "details": "细节", + "details": "详情", "devices": "客户设备", "entity-views": "客户实体视图", "events": "事件", @@ -618,10 +618,10 @@ "public-dashboards": "公共仪表板", "public-devices": "公共设备", "public-entity-views": "公共实体视图", - "search": "搜索客户", + "search": "查找客户", "select-customer": "选择客户", "select-default-customer": "选择默认的客户", - "selected-customers": "已选择 { count, plural, 1 {1 个客户} other {# 个客户} }", + "selected-customers": "已选择 { count, plural, 1 {# 个客户} other {# 个客户} }", "title": "标题", "title-required": "标题必填。" }, @@ -634,7 +634,7 @@ "assign-dashboard-to-customer": "将仪表板分配给客户", "assign-dashboard-to-customer-text": "请选择要分配给客户的仪表板", "assign-dashboards": "分配仪表板", - "assign-dashboards-text": "分配 { count, plural, 1 {1 个仪表板} other {# 个仪表板} } 给客户", + "assign-dashboards-text": "分配 { count, plural, 1 {# 个仪表板} other {# 个仪表板} } 给客户", "assign-new-dashboard": "分配新的仪表板", "assign-to-customer": "分配给客户", "assign-to-customer-text": "请选择客户分配仪表板", @@ -665,19 +665,19 @@ "delete-dashboard-text": "小心!确认后仪表板及其所有相关数据将不可恢复。", "delete-dashboard-title": "您确定要删除仪表板 '{{dashboardTitle}}'吗?", "delete-dashboards": "删除仪表板", - "delete-dashboards-action-title": "删除 { count, plural, 1 {1 个仪表板} other {# 个仪表板} }", + "delete-dashboards-action-title": "删除 { count, plural, 1 {# 个仪表板} other {# 个仪表板} }", "delete-dashboards-text": "小心!确认后所有选定的仪表板将被删除,所有相关数据将不可恢复。", - "delete-dashboards-title": "确定要删除 { count, plural, 1 {1 个仪表板} other {# 个仪表板} }吗?", + "delete-dashboards-title": "确定要删除 { count, plural, 1 {# 个仪表板} other {# 个仪表板} }吗?", "delete-state": "删除仪表板状态", "delete-state-text": "确定要删除仪表板状态 '{{stateName}}' 吗?", "delete-state-title": "删除仪表板状态", "description": "说明", - "details": "细节", + "details": "详情", "display-dashboard-export": "显示导出", "display-dashboard-timewindow": "显示时间窗口", "display-dashboards-selection": "显示仪表板选项", "display-entities-selection": "显示实体选项", - "display-filters": "显示过滤器", + "display-filters": "显示筛选器", "display-title": "显示仪表板标题", "drop-image": "拖拽图像或单击以选择要上传的文件。", "edit-state": "仪表板状态编辑", @@ -688,7 +688,7 @@ "horizontal-margin-required": "需要水平边距值。", "import": "导入仪表板", "import-widget": "导入部件", - "invalid-aliases-config": "无法找到与某些别名过滤器匹配的任何设备。
请联系您的管理员以解决此问题。", + "invalid-aliases-config": "无法找到与某些别名筛选器匹配的任何设备。
请联系您的管理员以解决此问题。", "invalid-dashboard-file-error": "无法导入仪表板: 仪表板数据结构无效。", "invalid-widget-file-error": "无法导入窗口部件: 窗口部件数据结构无效。", "is-root-state": "根状态", @@ -728,7 +728,7 @@ "public-dashboard-title": "仪表板现已公开", "public-link": "公共链接", "public-link-copied-message": "仪表板的公共链接已被复制到剪贴板", - "search": "搜索仪表板", + "search": "查找仪表板", "search-states": "仪表板状态检索", "select-dashboard": "选择仪表板", "select-devices": "选择设备", @@ -736,8 +736,8 @@ "select-state": "选择目标状态", "select-widget-subtitle": "可用的部件类型列表", "select-widget-title": "选择部件", - "selected-dashboards": "已选择 { count, plural, 1 {1 个仪表盘} other {# 个仪表盘} }", - "selected-states": "已选择 { count, plural, 1 {1 个仪表板状态} other {# 个仪表板状态} }", + "selected-dashboards": "已选择 { count, plural, 1 {# 个仪表盘} other {# 个仪表盘} }", + "selected-states": "已选择 { count, plural, 1 {# 个仪表板状态} other {# 个仪表板状态} }", "set-background": "设置背景", "settings": "设置", "show-details": "显示详情", @@ -759,10 +759,10 @@ "unassign-dashboard-text": "确认后,面板将被取消分配,客户将无法访问。", "unassign-dashboard-title": "您确定要取消分配仪表板 '{{dashboardTitle}}'吗?", "unassign-dashboards": "取消分配仪表板", - "unassign-dashboards-action-text": "取消分配 { count, plural, 1 {1 个仪表板} other {# 个仪表板} } 给客户", - "unassign-dashboards-action-title": "取消分配此客户 { count, plural, 1 {1 个仪表板} other {# 个仪表板} }", + "unassign-dashboards-action-text": "取消分配 { count, plural, 1 {# 个仪表板} other {# 个仪表板} } 给客户", + "unassign-dashboards-action-title": "取消分配此客户 { count, plural, 1 {# 个仪表板} other {# 个仪表板} }", "unassign-dashboards-text": "确认后,所有选定的仪表板将被取消分配,客户将无法访问。", - "unassign-dashboards-title": "确定要取消分配仪表板 { count, plural, 1 {1 个仪表板} other {# 个仪表板} } 吗?", + "unassign-dashboards-title": "确定要取消分配仪表板 { count, plural, 1 {# 个仪表板} other {# 个仪表板} } 吗?", "unassign-from-customer": "取消分配客户", "unassign-from-customers": "客户未分配仪表板", "unassign-from-customers-text": "请选择从仪表板中取消分配的客户", @@ -787,8 +787,8 @@ "function-types": "函数类型", "function-types-required": "需要函数类型。", "label": "标签", - "maximum-function-types": "最多允许 { count, plural, 1 {1 个函数类型} other {# 个函数类型} }", - "maximum-timeseries-or-attributes": "最多允许 { count, plural, 1 {1 个 timeseries/属性。} other {# 个 timeseries/属性。} }", + "maximum-function-types": "最多允许 { count, plural, 1 {# 个函数类型} other {# 个函数类型} }", + "maximum-timeseries-or-attributes": "最多允许 { count, plural, 1 {# 个 timeseries/属性。} other {# 个 timeseries/属性。} }", "prev-orig-value-description": "先前的原始值;", "prev-value-description": "上一次函数调用的结果;", "settings": "设置", @@ -813,7 +813,7 @@ "time-to": "时间到" }, "details": { - "details": "细节", + "details": "详情", "edit-json": "编辑JSON", "edit-mode": "编辑模式", "toggle-edit-mode": "切换编辑模式" @@ -821,14 +821,14 @@ "device-profile": { "add": "添加设备配置", "add-alarm-rule": "添加报警规则", - "add-alarm-rule-details": "添加详细信息", + "add-alarm-rule-details": "详情模板:", "add-clear-alarm-rule": "添加清除条件", "add-create-alarm-rule": "添加创建条件", "add-create-alarm-rule-prompt": "请添加创建报警规则", "advanced-settings": "高级设置", "alarm-details": "报警详细信息", "alarm-rule-condition": "报警规则条件", - "alarm-rule-details": "细节", + "alarm-rule-details": "详情", "alarm-rule-relation-types-list": "要传递的关联类型", "alarm-rule-relation-types-list-hint": "如果未选择传递关联类型,则将不按关联类型过滤而传递报警。", "alarm-rules": "报警规则", @@ -852,7 +852,7 @@ "condition-duration-value-range": "持续时间值应在1到2147483647之间。", "condition-duration-value-required": "持续时间值必填。", "condition-during": "在 {{during}} 期间", - "condition-repeat-times": "重复 { count, plural, 1 {1 次} other {# 次} }", + "condition-repeat-times": "重复 { count, plural, 1 {# 次} other {# 次} }", "condition-repeating-value": "事件计数", "condition-repeating-value-pattern": "事件计数应为整数。", "condition-repeating-value-range": "事件计数应在1到2147483647之间。", @@ -874,7 +874,7 @@ "delete-device-profile-text": "注意,确认后设备配置和所有相关数据将不可恢复。", "delete-device-profile-title": "是否确实要删除设备配置 '{{deviceProfileName}}'?", "delete-device-profiles-text": "请注意:确认后,所有选定的设备配置将被删除,所有相关数据将不可恢复。", - "delete-device-profiles-title": "确定要删除 { count, plural, 1 {1 个设备配置} other {# 个设备配置} }?", + "delete-device-profiles-title": "确定要删除 { count, plural, 1 {# 个设备配置} other {# 个设备配置} }?", "description": "说明", "device-profile": "设备配置", "device-profile-details": "设备配置详情", @@ -886,13 +886,13 @@ "edit-alarm-rule-condition": "编辑报警规则条件", "edit-schedule": "编辑报警日程表", "enter-alarm-rule-condition-prompt": "请添加报警规则条件", - "idCopiedMessage": "设备配置 Id 已复制到剪贴板", + "idCopiedMessage": "设备配置 ID 已复制到剪贴板", "mqtt-device-payload-type": "MQTT 设备 Payload", "mqtt-device-payload-type-json": "JSON", "mqtt-device-payload-type-proto": "Protobuf", "mqtt-device-topic-filters": "MQTT 设备 Topic 筛选器", "mqtt-device-topic-filters-unique": "MQTT设备 Topic 筛选器必须唯一。", - "mqtt-payload-type-required": "荷载类型必填。", + "mqtt-payload-type-required": "Payload 类型必填。", "multi-level-wildcards-hint": "[#]可以替换 topic filter 本身,并且必须是 topic 的最后一个符号。例如:# or v1/devices/me/#。", "name": "名称", "name-required": "名称是必需的。", @@ -922,9 +922,9 @@ "provision-strategy-required": "预配置策略必填。", "rpc-response-topic-filter": "RPC响应 Topic 筛选器", "rpc-response-topic-filter-required": "RPC响应 Topic 筛选器必填。", - "schedule": "地铁列车时刻表", - "schedule-any-time": "Active all the time", - "schedule-custom": "定制", + "schedule": "启用规则:", + "schedule-any-time": "始终启用", + "schedule-custom": "自定义启用", "schedule-day": { "friday": "星期五", "monday": "星期一", @@ -936,16 +936,16 @@ }, "schedule-days": "天", "schedule-days-of-week-required": "每周至少选择一天。", - "schedule-specific-time": "在特定时间活跃", + "schedule-specific-time": "定时启用", "schedule-time": "时间", "schedule-time-from": "从", "schedule-time-to": "到", "schedule-type": "计划程序类型", "schedule-type-required": "计划类型必填。", - "search": "搜索设备配置", + "search": "查找设备配置", "select-alarm-severity": "选择报警严重性", "select-queue-hint": "从下拉列表中选择或添加自定义名称。", - "selected-device-profiles": "已选择 { count, plural, 1 {1 个设备配置} other {# 个设备配置} }", + "selected-device-profiles": "已选择 { count, plural, 1 {# 个设备配置} other {# 个设备配置} }", "set-default": "设为默认设备配置", "set-default-device-profile-text": "确认后,设备配置将被标记为默认,并将用于未指定配置的新设备。", "set-default-device-profile-title": "确实要将设备配置 '{{deviceProfileName}}' 设为默认值吗?", @@ -983,7 +983,7 @@ "assign-device-to-customer": "将设备分配给客户", "assign-device-to-customer-text": "请选择要分配给客户的设备", "assign-devices": "分配设备", - "assign-devices-text": "将 {count,plural,1 {1 个设备} other {# 个设备} }分配给客户", + "assign-devices-text": "将 {count,plural,1 {# 个设备} other {# 个设备} }分配给客户", "assign-new-device": "分配新设备", "assign-to-customer": "分配给客户", "assign-to-customer-text": "请选择客户分配设备", @@ -1003,11 +1003,11 @@ "delete-device-text": "小心!确认后设备及其所有相关数据将不可恢复。", "delete-device-title": "您确定要删除设备的{{deviceName}}吗?", "delete-devices": "删除设备", - "delete-devices-action-title": "删除 {count,plural,1 {1 个设备} other {# 个设备} }", + "delete-devices-action-title": "删除 {count,plural,1 {# 个设备} other {# 个设备} }", "delete-devices-text": "小心!确认后所有选定的设备将被删除,所有相关数据将不可恢复。", - "delete-devices-title": "确定要删除{count,plural,1 {1 个设备} other {# 个设备} } 吗?", + "delete-devices-title": "确定要删除{count,plural,1 {# 个设备} other {# 个设备} } 吗?", "description": "说明", - "details": "细节", + "details": "详情", "device": "设备", "device-alias": "设备别名", "device-configuration": "设备配置", @@ -1017,7 +1017,7 @@ "device-list": "设备列表", "device-list-empty": "没有被选中的设备", "device-name-filter-no-device-matched": "找不到以'{{device}}' 开头的设备。", - "device-name-filter-required": "设备名称过滤器必填。", + "device-name-filter-required": "设备名称筛选器必填。", "device-public": "设备公开", "device-required": "设备必填", "device-type": "设备类型", @@ -1056,12 +1056,12 @@ "remove-alias": "删除设备别名", "rsa-key": "RSA公钥", "rsa-key-required": "RSA公钥必填", - "search": "搜索设备", + "search": "查找设备", "secret": "密钥", "secret-required": "密钥必填", "select-device": "选择设备", "select-device-type": "选择设备类型", - "selected-devices": "已选择 { count, plural, 1 {1 个设备} other {# 个设备} }", + "selected-devices": "已选择 { count, plural, 1 {# 个设备} other {# 个设备} }", "transport-configuration": "传输配置", "unable-delete-device-alias-text": "设备别名 '{{deviceAlias}}' 不能够被删除,因为它被下列部件所使用:
{{widgetsList}}", "unable-delete-device-alias-title": "无法删除设备别名", @@ -1069,11 +1069,11 @@ "unassign-device-text": "确认后,设备将被取消分配,客户将无法访问。", "unassign-device-title": "您确定要取消分配设备 '{{deviceName}}'?", "unassign-devices": "取消分配设备", - "unassign-devices-action-title": "取消分配此客户 {count,plural,1 {1 个设备} other {# 个设备} }", + "unassign-devices-action-title": "取消分配此客户 {count,plural,1 {# 个设备} other {# 个设备} }", "unassign-devices-text": "确认后,所有选定的设备将被取消分配,并且客户将无法访问。", - "unassign-devices-title": "确定要取消分配 {count,plural,1 {1 个设备} other {# 个设备} } 吗?", + "unassign-devices-title": "确定要取消分配 {count,plural,1 {# 个设备} other {# 个设备} } 吗?", "unassign-from-customer": "取消分配客户", - "use-device-name-filter": "使用过滤器", + "use-device-name-filter": "使用筛选器", "user-name": "用户名", "user-name-required": "用户名必填。", "view-credentials": "查看凭据", @@ -1123,7 +1123,7 @@ "assign-entity-view-to-customer": "将实体视图分配给客户", "assign-entity-view-to-customer-text": "请选择要分配给客户的实体视图", "assign-entity-views": "分配实体视图", - "assign-entity-views-text": "分配 { count, plural, 1 {1 个实体视图} other {# 个实体视图} } 给客户", + "assign-entity-views-text": "分配 { count, plural, 1 {# 个实体视图} other {# 个实体视图} } 给客户", "assign-new-entity-view": "分配新实体视图", "assign-to-customer": "分配给客户", "assign-to-customer-text": "请选择客户分配实体视图", @@ -1142,11 +1142,11 @@ "delete-entity-view-text": "小心!确认后实体视图及其所有相关数据将不可恢复。", "delete-entity-view-title": "确定要删除实体视图 '{{entityViewName}}'?", "delete-entity-views": "删除实体视图", - "delete-entity-views-action-title": "删除 { count, plural, 1 {1 个实体视图} other {# 个实体视图} }", + "delete-entity-views-action-title": "删除 { count, plural, 1 {# 个实体视图} other {# 个实体视图} }", "delete-entity-views-text": "请注意:确认后,所有选定的实体视图将被删除,所有相关的数据将变得不可恢复。", - "delete-entity-views-title": "确定要删除 { count, plural, 1 {1 实体视图} other {# 实体视图} }?", + "delete-entity-views-title": "确定要删除 { count, plural, 1 {# 实体视图} other {# 实体视图} }?", "description": "说明", - "details": "细节", + "details": "详情", "duplicate-alias-error": "找到重复别名 '{{alias}}'。
实体视图别名必须是唯一的。", "end-date": "结束日期", "end-ts": "结束时间", @@ -1157,7 +1157,7 @@ "entity-view-list": "实体视图列表", "entity-view-list-empty": "没有被选中的实体视图", "entity-view-name-filter-no-entity-view-matched": "找不到以'{{entityView}}' 开头的实体视图。", - "entity-view-name-filter-required": "实体视图名称过滤器必填。", + "entity-view-name-filter-required": "实体视图名称筛选器必填。", "entity-view-public": "实体视图是公共的", "entity-view-required": "实体视图必填。", "entity-view-type": "实体视图类型", @@ -1186,10 +1186,10 @@ "no-keys-found": "找不到密钥。", "public": "公开", "remove-alias": "删除实体视图别名", - "search": "搜索实体视图", + "search": "查找实体视图", "select-entity-view": "选择实体视图", "select-entity-view-type": "选择实体视图类型", - "selected-entity-views": "已选择 { count, plural, 1 {1 个实体视图} other {# 个实体视图} }", + "selected-entity-views": "已选择 { count, plural, 1 {# 个实体视图} other {# 个实体视图} }", "server-attributes": "服务端属性", "server-attributes-placeholder": "服务端属性", "shared-attributes": "共享属性", @@ -1207,11 +1207,11 @@ "unassign-entity-view-text": "确认后,实体视图将未分配,客户无法访问。", "unassign-entity-view-title": "您确定要取消对 '{{entityViewName}}'实体视图的分配吗?", "unassign-entity-views": "取消分配实体视图", - "unassign-entity-views-action-title": "从客户处取消分配{count,plural,1 {1 实体视图} other {# 实体视图} }", + "unassign-entity-views-action-title": "从客户处取消分配{count,plural,1 {# 实体视图} other {# 实体视图} }", "unassign-entity-views-text": "确认后,所有选定的实体视图将被分配,客户无法访问。", - "unassign-entity-views-title": "确定要取消分配 { count, plural, 1 {1 个实体视图} other {# 个实体视图} }吗?", + "unassign-entity-views-title": "确定要取消分配 { count, plural, 1 {# 个实体视图} other {# 个实体视图} }吗?", "unassign-from-customer": "取消分配客户", - "use-entity-view-name-filter": "使用过滤器", + "use-entity-view-name-filter": "使用筛选器", "view-entity-views": "查看实体视图" }, "entity": { @@ -1242,14 +1242,14 @@ "entity-list-empty": "没有选择实体。", "entity-name": "实体名", "entity-name-filter-no-entity-matched": "没有找到以 '{{entity}}' 开头的实体", - "entity-name-filter-required": "实体名过滤器必填。", + "entity-name-filter-required": "实体名筛选器必填。", "entity-type": "实体类型", "entity-type-list": "实体类型列表", "entity-type-list-empty": "没有选择实体类型。", "entity-types": "实体类型", "entity-view-name-starts-with": "以 '{{prefix}}' 开头的实体视图", "key": "键名", - "key-name": "密钥名称", + "key-name": "Key name", "list-of-alarms": "{ count, plural, 1 {个警告} other {# 个警告} }", "list-of-assets": "{ count, plural, 1 {个资产} other {# 个资产} }", "list-of-customers": "{ count, plural, 1 {个客户} other {# 个客户} }", @@ -1281,7 +1281,7 @@ "rulenode-name-starts-with": "名称以 '{{prefix}}' 开头的规则节点", "search": "实体检索", "select-entities": "选择实体", - "selected-entities": "已选择 { count, plural, 1 {1 个实体} other {# 个实体} }", + "selected-entities": "已选择 { count, plural, 1 {# 个实体} other {# 个实体} }", "tenant-name-starts-with": "以 '{{prefix}}' 开头的租户", "tenant-profile-name-starts-with": "名称以 '{{prefix}}' 开头的租户配置", "type": "类型", @@ -1321,7 +1321,7 @@ "type-users": "用户", "unable-delete-entity-alias-text": "实体别名 '{{entityAlias}}' 被以下部件使用不能删除:
{{widgetsList}}", "unable-delete-entity-alias-title": "无法删除实体别名", - "use-entity-name-filter": "用户过滤", + "use-entity-name-filter": "用户筛选器", "user-name-starts-with": "以 '{{prefix}}' 开头的用户" }, "error": { @@ -1374,9 +1374,9 @@ "add-timeseries": "添加 Timeseries", "anonymous": "匿名", "attr-json-key-expression": "属性键JSON表达式", - "attr-topic-key-expression": "属性关键字主题表达式", + "attr-topic-key-expression": "属性键名Topic表达式", "attribute-filter": "属性筛选器", - "attribute-key-expression": "属性关键字表达式", + "attribute-key-expression": "属性键名表达式", "attribute-requests": "属性请求", "attribute-updates": "属性更新", "attributes": "属性", @@ -1400,7 +1400,7 @@ "delete-extension-text": "请注意:确认后,扩展和所有相关数据将变得不可恢复。", "delete-extension-title": "确实要删除扩展名'{{extensionId}}'吗?", "delete-extensions-text": "请注意:确认后,所有选定的扩展将被删除。", - "delete-extensions-title": "确定要删除 { count, plural, 1 {1 个扩展} other {# 个扩展} }吗?", + "delete-extensions-title": "确定要删除 { count, plural, 1 {# 个扩展} other {# 个扩展} }吗?", "device-name-expression": "设备名称表达式", "device-name-filter": "设备名称筛选器", "device-type-expression": "设备类型表达式", @@ -1414,7 +1414,7 @@ "extensions": "扩展", "field-required": "必填字段", "file": "扩展文件", - "filter-expression": "过滤表达式", + "filter-expression": "筛选条件表达式", "host": "主机", "id": "ID", "import-extension": "导入扩展", @@ -1488,7 +1488,7 @@ "response-timeout": "毫秒内响应超时", "response-topic-expression": "响应主题表达式", "retry-interval": "以毫秒为单位的重试间隔", - "selected-extensions": "已选择 { count, plural, 1 {1 个扩展} other {# 个扩展} }", + "selected-extensions": "已选择 { count, plural, 1 {# 个扩展} other {# 个扩展} }", "server-side-rpc": "服务端RPC", "ssl": "Ssl", "sync": { @@ -1504,7 +1504,7 @@ "token": "安全令牌", "topic": "主题", "topic-expression": "主题表达", - "topic-filter": "主题滤波", + "topic-filter": "Topic筛选器", "topic-name-expression": "设备名称主题表达式", "topic-type-expression": "设备类型主题表达式", "transformer": "转换器", @@ -1517,14 +1517,14 @@ }, "filter": { "add": "添加筛选器", - "add-complex": "Add complex", + "add-complex": "添加复合", "add-complex-filter": "添加复合筛选器", "add-filter": "添加筛选器", "add-filter-prompt": "请添加筛选器", - "add-key-filter": "添加密钥筛选器", + "add-key-filter": "添加键名筛选器", "autogenerated-label": "自动生成标签", "complex-filter": "复合筛选器", - "create-new-filter": "创建一个新的!", + "create-new-filter": "请新增!", "current-customer": "当前客户", "current-device": "当前设备", "current-tenant": "当前租户", @@ -1538,26 +1538,26 @@ "edit": "编辑筛选器", "edit-complex-filter": "编辑复合筛选器", "edit-filter-user-params": "编辑筛选器谓词用户参数", - "edit-key-filter": "Edit key filter", + "edit-key-filter": "编辑键名筛选器", "editable": "可编辑", "filter": "筛选器", "filter-required": "筛选器必填。", "filter-user-params": "过滤谓词用户参数", - "filters": "过滤器", + "filters": "筛选器", "ignore-case": "忽略大小写", - "key-filter": "Key filter", - "key-filters": "Key filters", - "key-name": "Key name", - "key-name-required": "Key name 必填。", + "key-filter": "键名筛选器", + "key-filters": "键名筛选器", + "key-name": "键名", + "key-name-required": "键名必填。", "key-type": { "attribute": "属性", - "entity-field": "实体字段", - "key-type": "Key type", + "entity-field": "实体", + "key-type": "键类型", "timeseries": "Timeseries" }, "key-value-type-change-message": "如果您确认新的值类型,所有输入的键过滤器将被删除。", "key-value-type-change-title": "是否确实要更改键值类型?", - "missing-key-filters-error": "Key filters is missing for filter '{{filter}}'.", + "missing-key-filters-error": "筛选器 '{{filter}}' 的键名筛选条件缺失。", "name": "筛选器名称", "name-required": "筛选器名称必填。", "no-dynamic-value": "无动态值", @@ -1565,18 +1565,18 @@ "no-filter-text": "未指定筛选器", "no-filters": "未配置筛选器", "no-filters-found": "找不到筛选器。", - "no-key-filters": "未配置密钥筛选器", + "no-key-filters": "未配置键名筛选器", "operation": { "and": "和", "contains": "包含", "ends-with": "结束于", - "equal": "平等的", + "equal": "等于", "greater": "大于", "greater-or-equal": "大于或等于", "less": "小于", "less-or-equal": "小于或等于", "not-contains": "不包含", - "not-equal": "不相等", + "not-equal": "不等于", "operation": "操作", "or": "或", "starts-with": "开始于" @@ -1584,7 +1584,7 @@ "order-priority": "字段顺序优先级", "preview": "筛选器预览", "remove-filter": "删除筛选器", - "remove-key-filter": "Remove key filter", + "remove-key-filter": "删除键名筛选器", "source-attribute": "源属性", "switch-to-default-value": "切换到默认值", "switch-to-dynamic-value": "切换到动态值", @@ -1592,7 +1592,7 @@ "unable-delete-filter-text": "无法删除筛选器 '{{filter}}' ,因为它由以下小部件使用:
{{widgetsList}}", "unable-delete-filter-title": "无法删除筛选器", "user-parameters": "用户参数", - "value": "价值", + "value": "值", "value-type-required": "键值类型是必需的。", "value-type": { "boolean": "布尔值", @@ -1691,9 +1691,9 @@ "delete-item-text": "注意,确认后此项及其所有相关数据将变得不可恢复。", "delete-item-title": "您确定要删除此项吗?", "delete-items": "删除项目", - "delete-items-action-title": "删除 { count, plural, 1 {1 个元素} other {# 个元素} }", + "delete-items-action-title": "删除 { count, plural, 1 {# 个元素} other {# 个元素} }", "delete-items-text": "注意,确认后所有选择的项目将被删除,所有相关数据将不可恢复。", - "delete-items-title": "确定你要删除 { count, plural, 1 {1 项} other {# 项} }吗?", + "delete-items-title": "确定你要删除 { count, plural, 1 {# 项} other {# 项} }吗?", "item-details": "项目详细信息", "no-items-text": "没有找到项目", "scroll-to-top": "滚动到顶部" @@ -1865,7 +1865,7 @@ }, "relation": { "add": "添加关联", - "add-relation-filter": "添加关联过滤器", + "add-relation-filter": "添加关联筛选器", "additional-info": "附加信息 (JSON)", "any-relation": "任意关联", "any-relation-type": "任何类型", @@ -1873,11 +1873,11 @@ "delete-from-relation-text": "确定删除后,当前实体将与实体 '{{entityName}}' 取消关联", "delete-from-relation-title": "确定要从实体 '{{entityName}}' 删除关联吗?", "delete-from-relations-text": "确定删除所有选择的关联关系后,当前实体将与对应的实体取消关联", - "delete-from-relations-title": "确定删除 { count, plural, 1 {1 个关联} other {# 个关联} } 吗?", + "delete-from-relations-title": "确定删除 { count, plural, 1 {# 个关联} other {# 个关联} } 吗?", "delete-to-relation-text": "确定删除后实体 '{{entityName}}' 将取消与当前实体的关联关系。", "delete-to-relation-title": "确定要删除实体 '{{entityName}}' 的关联吗?", "delete-to-relations-text": "确定删除所有选择的关联关系后,与当前实体对应的所有关联关系将被移除。", - "delete-to-relations-title": "确定要删除 { count, plural, 1 {1 个关联} other {# 个关联} }?", + "delete-to-relations-title": "确定要删除 { count, plural, 1 {# 个关联} other {# 个关联} }?", "direction": "方向", "direction-type": { "FROM": "从", @@ -1890,16 +1890,16 @@ "from-relations": "向外的关联", "invalid-additional-info": "无法解析附加信息JSON。", "no-relations-text": "未找到关联", - "relation-filters": "关联过滤器", + "relation-filters": "关联筛选器", "relation-type": "关联类型", "relation-type-required": "关联类型必填", "relations": "关联", - "remove-relation-filter": "移除关联过滤器", + "remove-relation-filter": "移除关联筛选器", "search-direction": { "FROM": "从", "TO": "到" }, - "selected-relations": "已选择{ count, plural, 1 {1 个关联} other {# 个关联} }", + "selected-relations": "已选择{ count, plural, 1 {# 个关联} other {# 个关联} }", "to-entity": "到实体", "to-entity-name": "到实体名称", "to-entity-type": "到实体类型", @@ -1915,11 +1915,11 @@ "delete": "删除规则链", "delete-rulechain-text": "小心,在确认规则链和所有相关数据将变得不可恢复。", "delete-rulechain-title": " 确实要删除规则链'{{ruleChainName}}'吗?", - "delete-rulechains-action-title": "删除 { count, plural, 1 {1 个规则链} other {# 个规则链} }", + "delete-rulechains-action-title": "删除 { count, plural, 1 {# 个规则链} other {# 个规则链} }", "delete-rulechains-text": "请注意:确认后,所有选定的规则链将被删除,所有相关的数据将变得不可恢复。", "delete-rulechains-title": "确实要删除{count, plural, 1 { 1 个规则链} other {# 个规则链} }吗?", "description": "说明", - "details": "细节", + "details": "详情", "events": "事件", "export": "导出规则链", "export-failed-error": "无法导出规则链:{{error}}", @@ -1938,9 +1938,9 @@ "rulechain-file": "规则链文件", "rulechain-required": "规则链必填", "rulechains": "规则链库", - "search": "搜索规则链", + "search": "查找规则链", "select-rulechain": "选择规则链", - "selected-rulechains": "已选择 { count, plural, 1 {1 个规则链} other {# 个规则链} }", + "selected-rulechains": "已选择 { count, plural, 1 {# 个规则链} other {# 个规则链} }", "set-root": "设置为根规则链", "set-root-rulechain-text": "确认之后,规则链将变为根规格链,并将处理所有传入的传输消息。", "set-root-rulechain-title": "您确定要生成规则链'{{RuleChainName}}'根吗?", @@ -1961,7 +1961,7 @@ "description": "说明", "deselect-all": "取消选择", "deselect-all-objects": "取消选择所有节点和连接", - "details": "细节", + "details": "详情", "directive-is-not-loaded": "定义的配置指令 '{{directiveName}}' 不可用。", "events": "事件", "help": "帮助", @@ -1985,7 +1985,7 @@ "output": "输出", "reset-debug-mode": "重置所有节点中的调试模式", "rulenode-details": "规则节点详情", - "search": "搜索节点", + "search": "查找节点", "select-all": "选择全部", "select-all-objects": "选择所有节点和连接", "select-message-type": "选择消息类型", @@ -1998,14 +1998,14 @@ "type-enrichment-details": "向消息元数据中添加附加信息", "type-external": "外部的", "type-external-details": "与外部系统交互", - "type-filter": "过滤器", - "type-filter-details": "使用配置条件过滤传入消息", + "type-filter": "筛选器", + "type-filter-details": "使用配置条件筛选传入消息", "type-input": "输入", "type-input-details": "规则链的逻辑输入,将传入消息转发到下一个相关规则节点", "type-rule-chain": "规则链", "type-rule-chain-details": "将传入消息转发到指定的规则链", "type-transformation": "变换", - "type-transformation-details": "更改消息有效载荷和元数据", + "type-transformation-details": "更改消息 Payload 和元数据", "type-unknown": "未知", "type-unknown-details": "未解析的规则节点", "ui-resources-load-error": "加载配置UI资源失败。" @@ -2023,7 +2023,7 @@ "delete-tenant-profile-text": "请注意:确认后,租户配置和所有相关数据将不可。", "delete-tenant-profile-title": "确实要删除租户配置 '{{tenantProfileName}}'吗?", "delete-tenant-profiles-text": "请注意:确认后,所有选定的租户配置将被删除,所有相关数据将不可恢复。", - "delete-tenant-profiles-title": "确定要删除 { count, plural, 1 {1 个租户配置} other {# 个租户配置} }?", + "delete-tenant-profiles-title": "确定要删除 { count, plural, 1 {# 个租户配置} other {# 个租户配置} }?", "description": "说明", "edit": "编辑租户配置", "idCopiedMessage": "租户配置Id已复制到剪贴板", @@ -2075,8 +2075,8 @@ "no-tenant-profiles-matching": "找不到与 '{{entity}}' 匹配的租户配置。", "no-tenant-profiles-text": "找不到租户配置", "profile-configuration": "配置设置", - "search": "搜索租户配置", - "selected-tenant-profiles": "已选择 { count, plural, 1 {1 个租户配置} other {# 个租户配置} }", + "search": "查找租户配置", + "selected-tenant-profiles": "已选择 { count, plural, 1 {# 个租户配置} other {# 个租户配置} }", "set-default": "设置该租户配置为默认", "set-default-tenant-profile-text": "确认后,此租户配置将被标记为默认配置,并将用于未指定配置的新租户。", "set-default-tenant-profile-title": "确实要将租户配置 '{{tenantProfileName}}' 设为默认值吗?", @@ -2099,11 +2099,11 @@ "delete": "删除租户", "delete-tenant-text": "小心!确认后,租户和所有相关数据将不可恢复。", "delete-tenant-title": "您确定要删除租户'{{tenantTitle}}'吗?", - "delete-tenants-action-title": "删除 { count, plural, 1 {1 个租户} other {# 个租户} }", + "delete-tenants-action-title": "删除 { count, plural, 1 {# 个租户} other {# 个租户} }", "delete-tenants-text": "小心!确认后,所有选定的租户将被删除,所有相关数据将不可恢复。", - "delete-tenants-title": "确定要删除 {count,plural,1 {1 个租户} other {# 个租户} } 吗?", + "delete-tenants-title": "确定要删除 {count,plural,1 {# 个租户} other {# 个租户} } 吗?", "description": "说明", - "details": "细节", + "details": "详情", "events": "事件", "idCopiedMessage": "租户ID已经复制到粘贴板", "isolated-tb-core": "隔离板芯容器中的加工", @@ -2114,9 +2114,9 @@ "management": "租户管理", "no-tenants-matching": "没有找到符合 '{{entity}}' 的租户", "no-tenants-text": "没有找到租户", - "search": "搜索租户", + "search": "查找租户", "select-tenant": "选择租户", - "selected-tenants": "已选择 { count, plural, 1 {1 个租户} other {# 个租户} }", + "selected-tenants": "已选择 { count, plural, 1 {# 个租户} other {# 个租户} }", "tenant": "租户", "tenant-details": "租客详情", "tenant-required": "租户必填", @@ -2127,13 +2127,13 @@ "timeinterval": { "advanced": "高级", "days": "天", - "days-interval": "{ days, plural, 1 {1 天} other {# 天} }", + "days-interval": "{ days, plural, 1 {# 天} other {# 天} }", "hours": "小时", - "hours-interval": "{ hours, plural, 1 {1 小时} other {# 小时} }", + "hours-interval": "{ hours, plural, 1 {# 小时} other {# 小时} }", "minutes": "分钟", - "minutes-interval": "{ minutes, plural, 1 {1 分} other {# 分} }", + "minutes-interval": "{ minutes, plural, 1 {# 分} other {# 分} }", "seconds": "秒", - "seconds-interval": "{ seconds, plural, 1 {1 秒} other {# 秒} }" + "seconds-interval": "{ seconds, plural, 1 {# 秒} other {# 秒} }" }, "timeunit": { "days": "天", @@ -2143,17 +2143,17 @@ }, "timewindow": { "date-range": "日期范围", - "days": "{ days, plural, 1 { 天 } other {# 天 } }", + "days": "{ days, plural, 1 {# 天 } other {# 天 } }", "edit": "编辑时间窗口", "hide": "隐藏", "history": "历史", - "hours": "{ hours, plural, 0 { 小时 } 1 {1 小时 } other {# 小时 } }", + "hours": "{ hours, plural, 0 {- 小时 } 1 {# 小时 } other {# 小时 } }", "last": "最后", "last-prefix": "最后", - "minutes": "{ minutes, plural, 0 { 分 } 1 {1 分 } other {# 分 } }", + "minutes": "{ minutes, plural, 0 {- 分 } 1 {# 分 } other {# 分 } }", "period": "从 {{ startTime }} 到 {{ endTime }}", "realtime": "实时", - "seconds": "{ seconds, plural, 0 { 秒 } 1 {1 秒 } other {# 秒 } }", + "seconds": "{ seconds, plural, 0 {- 秒 } 1 {# 秒 } other {# 秒 } }", "time-period": "时间段" }, "timezone": { @@ -2179,11 +2179,11 @@ "delete": "删除用户", "delete-user-text": "小心!确认后,用户和所有相关数据将不可恢复。", "delete-user-title": "您确定要删除用户 '{{userEmail}}' 吗?", - "delete-users-action-title": "删除 { count, plural, 1 {1 个用户} other {# 个用户} }", + "delete-users-action-title": "删除 { count, plural, 1 {# 个用户} other {# 个用户} }", "delete-users-text": "小心!确认后,所有选定的用户将被删除,所有相关数据将不可恢复。", - "delete-users-title": "确定要删除 { count, plural, 1 {1 个用户} other {# 个用户} } 吗?", + "delete-users-title": "确定要删除 { count, plural, 1 {# 个用户} other {# 个用户} } 吗?", "description": "说明", - "details": "细节", + "details": "详情", "disable-account": "禁用用户帐户", "disable-account-message": "已成功禁用用户帐户!", "display-activation-link": "显示激活链接", @@ -2199,9 +2199,9 @@ "no-users-matching": "没有找到符合 '{{entity}}' 的用户。", "no-users-text": "找不到用户", "resend-activation": "重新发送激活", - "search": "搜索用户", + "search": "查找用户", "select-user": "选择用户", - "selected-users": "已选择 { count, plural, 1 {1 个用户} other {# 个用户} }", + "selected-users": "已选择 { count, plural, 1 {# 个用户} other {# 个用户} }", "send-activation-mail": "发送激活邮件", "sys-admin": "系统管理员", "tenant-admin": "租户管理员", @@ -2277,12 +2277,12 @@ "drop-shadow": "阴影", "edit-action": "编辑 Action", "enable-fullscreen": "启用全屏", - "general-settings": "常规设置", + "general-settings": "基本设置", "height": "高度", "icon-color": "图标颜色", "icon-size": "图标大小", "margin": "边缘", - "maximum-datasources": "最大允许 { count, plural, 1 {1 个数据源。} other {# 个数据源。} }", + "maximum-datasources": "最大允许 { count, plural, 1 {# 个数据源。} other {# 个数据源。} }", "mobile-mode-settings": "移动端设置", "no-actions-text": "找不到 Action", "order": "顺序", @@ -2344,7 +2344,7 @@ "save-widget-type-as": "部件类型另存为", "save-widget-type-as-text": "请输入新的部件标题或选择目标部件组", "saveAs": "部件另存为", - "search-data": "搜索数据", + "search-data": "查找数据", "select-widget-type": "选择窗口部件类型", "select-widgets-bundle": "选择部件组", "settings-schema": "设置模式", @@ -2373,10 +2373,10 @@ "delete": "删除部件组", "delete-widgets-bundle-text": "小心!确认后,部件组和所有相关数据将不可恢复。", "delete-widgets-bundle-title": "您确定要删除部件组 '{{widgetsBundleTitle}}'吗?", - "delete-widgets-bundles-action-title": "删除 { count, plural, 1 {1 个部件组} other {# 个部件组} }", + "delete-widgets-bundles-action-title": "删除 { count, plural, 1 {# 个部件组} other {# 个部件组} }", "delete-widgets-bundles-text": "小心!确认后,所有选定的部件组将被删除,所有相关数据将不可恢复。", - "delete-widgets-bundles-title": "确定要删除 { count, plural, 1 {1 个部件组} other {# 个部件组} } 吗?", - "details": "细节", + "delete-widgets-bundles-title": "确定要删除 { count, plural, 1 {# 个部件组} other {# 个部件组} } 吗?", + "details": "详情", "empty": "部件组是空的", "export": "导出部件组", "export-failed-error": "无法导出部件组: {{error}}", @@ -2385,8 +2385,8 @@ "no-widgets-bundles-matching": "没有找到与 '{{widgetsBundle}}' 匹配的部件组。", "no-widgets-bundles-text": "找不到部件组", "open-widgets-bundle": "打开部件组", - "search": "搜索部件组", - "selected-widgets-bundles": "已选择 { count, plural, 1 {1 个部件组} other {# 个部件组} }", + "search": "查找部件组", + "selected-widgets-bundles": "已选择 { count, plural, 1 {# 个部件组} other {# 个部件组} }", "system": "系统", "title": "标题", "title-required": "标题必填。", From 573837c4b126e19428a67933dbc6b2d9bbe10240 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Thu, 21 Jan 2021 17:38:45 +0200 Subject: [PATCH 054/249] Lwm2m: front: refactoring sort json and add instances --- .../LWM2M_Connectivity_Monitoring-v1_0_2.xml | 208 ------------------ .../LWM2M_Connectivity_Monitoring-v1_0_2.xml | 167 -------------- ...ofile-transport-configuration.component.ts | 20 +- .../lwm2m/lwm2m-object-list.component.html | 2 +- .../lwm2m-observe-attr-telemetry.component.ts | 62 +++--- 5 files changed, 48 insertions(+), 411 deletions(-) delete mode 100644 common/transport/lwm2m/src/main/resources/models/LWM2M_Connectivity_Monitoring-v1_0_2.xml delete mode 100644 transport/lwm2m/src/main/data/models/LWM2M_Connectivity_Monitoring-v1_0_2.xml diff --git a/common/transport/lwm2m/src/main/resources/models/LWM2M_Connectivity_Monitoring-v1_0_2.xml b/common/transport/lwm2m/src/main/resources/models/LWM2M_Connectivity_Monitoring-v1_0_2.xml deleted file mode 100644 index 28957f5a5d..0000000000 --- a/common/transport/lwm2m/src/main/resources/models/LWM2M_Connectivity_Monitoring-v1_0_2.xml +++ /dev/null @@ -1,208 +0,0 @@ - - - - - Connectivity Monitoring - - This LwM2M Object enables monitoring of parameters related to network connectivity. In this general connectivity Object, the Resources are limited to the most general cases common to most network bearers. It is recommended to read the description, which refers to relevant standard development organizations (e.g. 3GPP, IEEE). The goal of the Connectivity Monitoring Object is to carry information reflecting the more up to date values of the current connection for monitoring purposes. Resources such as Link Quality, Radio Signal Strength, Cell ID are retrieved during connected mode at least for cellular networks. - - 4 - urn:oma:lwm2m:oma:4 - 1.0 - 1.0 - Single - Optional - - - Network Bearer - R - Single - Mandatory - Integer - 0-50 - - - Indicates the network bearer used for the current LwM2M communication session from the network bearer list below. The number range is split into three categories: 0 - 20 are Cellular Bearers 21 - 40 are Wireless Bearers 41 - 50 are Wireline Bearers More specifically: 0: GSM cellular network 1: TD-SCDMA cellular network 2: WCDMA cellular network 3: CDMA2000 cellular network 4: WiMAX cellular network 5: LTE-TDD cellular network 6: LTE-FDD cellular network 7: NB-IoT 8 - 20: Reserved for other types of cellular network 21: WLAN network 22: Bluetooth network 23: IEEE 802.15.4 network 24 - 40: Reserved for other types of local wireless network 41: Ethernet 42: DSL 43: PLC 44 - 50: reserved for other types of wireline networks. - - - - Available Network Bearer - R - Multiple - Mandatory - Integer - 0-50 - - - Indicates a list of current available network bearer. Each Resource Instance has a value from the network bearer list. - - - - Radio Signal Strength - R - Single - Mandatory - Integer - - dBm - - Indicates the average value of the received signal strength indication used in the current network bearer (as indicated by Resource 0 of this Object). For the following network bearers the signal strength parameters indicated below are represented by this resource: GSM: RSSI UMTS: RSCP LTE: RSRP NB-IoT: NRSRP For more details on Network Measurement Report, refer to the appropriate Cellular or Wireless Network standards, (e.g. for LTE Cellular Network refer to 3GPP TS 36.133 specification). - - - - Link Quality - R - Single - Optional - Integer - - - - This contains received link quality e.g. LQI for IEEE 802.15.4 (range 0...255), RxQual Downlink for GSM (range 0...7, refer to [3GPP 44.018] for more details on Network Measurement Report encoding), RSRQ for LTE, (refer to [3GPP 36.214]), NRSRQ for NB-IoT (refer to [3GPP 36.214]). - - - - IP Addresses - R - Multiple - Mandatory - String - - - - The IP addresses assigned to the connectivity interface. (e.g. IPv4, IPv6, etc.) - - - - Router IP Addresses - R - Multiple - Optional - String - - - - The IP address of the next-hop IP router, on each of the interfaces specified in resource 4 (IP Addresses). Note: This IP Address doesn’t indicate the Server IP address. - - - - Link Utilization - R - Single - Optional - Integer - 0-100 - % - - The percentage indicating the average utilization of the link to the next-hop IP router. - - - - APN - R - Multiple - Optional - String - - - - Access Point Name in case Network Bearer Resource is a Cellular Network. - - - - Cell ID - R - Single - Optional - Integer - - - - Serving Cell ID in case Network Bearer Resource is a Cellular Network. As specified in TS [3GPP 23.003] and in [3GPP. 24.008]. Range (0...65535) in GSM/EDGE UTRAN Cell ID has a length of 28 bits. Cell Identity in WCDMA/TD-SCDMA. Range: (0...268435455). LTE Cell ID has a length of 28 bits. Parameter definitions in [3GPP 25.331]. - - - - SMNC - R - Single - Optional - Integer - 0-999 - % - - Serving Mobile Network Code. This is applicable when the Network Bearer Resource value is referring to a cellular network. As specified in TS [3GPP 23.003]. - - - - SMCC - R - Single - Optional - Integer - 0-999 - - - Serving Mobile Country Code. This is applicable when the Network Bearer Resource value is referring to a cellular network. As specified in TS [3GPP 23.003]. - - - - - - diff --git a/transport/lwm2m/src/main/data/models/LWM2M_Connectivity_Monitoring-v1_0_2.xml b/transport/lwm2m/src/main/data/models/LWM2M_Connectivity_Monitoring-v1_0_2.xml deleted file mode 100644 index 48e942983d..0000000000 --- a/transport/lwm2m/src/main/data/models/LWM2M_Connectivity_Monitoring-v1_0_2.xml +++ /dev/null @@ -1,167 +0,0 @@ - - - - - Connectivity Monitoring - - This LwM2M Object enables monitoring of parameters related to network connectivity. In this general connectivity Object, the Resources are limited to the most general cases common to most network bearers. It is recommended to read the description, which refers to relevant standard development organizations (e.g. 3GPP, IEEE). The goal of the Connectivity Monitoring Object is to carry information reflecting the more up to date values of the current connection for monitoring purposes. Resources such as Link Quality, Radio Signal Strength, Cell ID are retrieved during connected mode at least for cellular networks. - - 4 - urn:oma:lwm2m:oma:4 - 1.0 - 1.0 - Single - Optional - - - Network Bearer - R - Single - Mandatory - Integer - 0-50 - - - Indicates the network bearer used for the current LwM2M communication session from the network bearer list below. The number range is split into three categories: 0 - 20 are Cellular Bearers 21 - 40 are Wireless Bearers 41 - 50 are Wireline Bearers More specifically: 0: GSM cellular network 1: TD-SCDMA cellular network 2: WCDMA cellular network 3: CDMA2000 cellular network 4: WiMAX cellular network 5: LTE-TDD cellular network 6: LTE-FDD cellular network 7: NB-IoT 8 - 20: Reserved for other types of cellular network 21: WLAN network 22: Bluetooth network 23: IEEE 802.15.4 network 24 - 40: Reserved for other types of local wireless network 41: Ethernet 42: DSL 43: PLC 44 - 50: reserved for other types of wireline networks. - - - - Available Network Bearer - R - Multiple - Mandatory - Integer - 0-50 - - - Indicates a list of current available network bearer. Each Resource Instance has a value from the network bearer list. - - - - Radio Signal Strength - R - Single - Mandatory - Integer - - dBm - - Indicates the average value of the received signal strength indication used in the current network bearer (as indicated by Resource 0 of this Object). For the following network bearers the signal strength parameters indicated below are represented by this resource: GSM: RSSI UMTS: RSCP LTE: RSRP NB-IoT: NRSRP For more details on Network Measurement Report, refer to the appropriate Cellular or Wireless Network standards, (e.g. for LTE Cellular Network refer to 3GPP TS 36.133 specification). - - - - Link Quality - R - Single - Optional - Integer - - - - This contains received link quality e.g. LQI for IEEE 802.15.4 (range 0...255), RxQual Downlink for GSM (range 0...7, refer to [3GPP 44.018] for more details on Network Measurement Report encoding), RSRQ for LTE, (refer to [3GPP 36.214]), NRSRQ for NB-IoT (refer to [3GPP 36.214]). - - - - IP Addresses - R - Multiple - Mandatory - String - - - - The IP addresses assigned to the connectivity interface. (e.g. IPv4, IPv6, etc.) - - - - Router IP Addresses - R - Multiple - Optional - String - - - - The IP address of the next-hop IP router, on each of the interfaces specified in resource 4 (IP Addresses). Note: This IP Address doesn’t indicate the Server IP address. - - - - Link Utilization - R - Single - Optional - Integer - 0-100 - % - - The percentage indicating the average utilization of the link to the next-hop IP router. - - - - APN - R - Multiple - Optional - String - - - - Access Point Name in case Network Bearer Resource is a Cellular Network. - - - - Cell ID - R - Single - Optional - Integer - - - - Serving Cell ID in case Network Bearer Resource is a Cellular Network. As specified in TS [3GPP 23.003] and in [3GPP. 24.008]. Range (0...65535) in GSM/EDGE UTRAN Cell ID has a length of 28 bits. Cell Identity in WCDMA/TD-SCDMA. Range: (0...268435455). LTE Cell ID has a length of 28 bits. Parameter definitions in [3GPP 25.331]. - - - - SMNC - R - Single - Optional - Integer - 0-999 - % - - Serving Mobile Network Code. This is applicable when the Network Bearer Resource value is referring to a cellular network. As specified in TS [3GPP 23.003]. - - - - SMCC - R - Single - Optional - Integer - 0-999 - - - Serving Mobile Country Code. This is applicable when the Network Bearer Resource value is referring to a cellular network. As specified in TS [3GPP 23.003]. - - - - - - diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts index feb248d5cc..5ce7620e32 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts @@ -73,7 +73,8 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro this.requiredValue = coerceBooleanProperty(value); } - private propagateChange = (v: any) => { }; + private propagateChange = (v: any) => { + }; constructor(private store: Store, private fb: FormBuilder, @@ -403,19 +404,26 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro sortObjectKeyPathJson = (key: string, value: object): object => { if (key === 'keyName') { - return Object.keys(value).sort((a, b) => { - const aLC = Array.from(a.substring(1).split('/'), Number); - const bLC = Array.from(b.substring(1).split('/'), Number); - return aLC[0] === bLC[0] ? aLC[1] - bLC[1] : aLC[0] - bLC[0]; - }).reduce((obj, keySort) => { + return Object.keys(value).sort(this.sortPath).reduce((obj, keySort) => { obj[keySort] = value[keySort]; return obj; }, {}); + } else if (key === 'observe' || key === 'attribute' || key === 'telemetry') { + return Object.values(value).sort(this.sortPath).reduce((arr, arrValue) => { + arr.push(arrValue); + return arr; + }, []); } else { return value; } } + private sortPath = (a, b): number => { + const aLC = Array.from(a.substring(1).split('/'), Number); + const bLC = Array.from(b.substring(1).split('/'), Number); + return aLC[0] === bLC[0] ? aLC[1] - bLC[1] : aLC[0] - bLC[0]; + } + private updateKeyName = (): void => { const paths = new Set(); if (this.configurationValue[this.observeAttr][this.attribute]) { diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.html index 260f0016f5..09b2abfe44 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.html @@ -41,7 +41,7 @@ class="tb-autocomplete" [displayWith]="displayObjectLwm2mFn"> - + diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts index f6a600ae99..4122971e50 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts @@ -89,7 +89,6 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor private propagateChange = (v: any) => { }; - registerOnChange(fn: any): void { this.propagateChange = fn; } @@ -164,7 +163,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor } changeInstanceResourcesCheckBox = (value: boolean, instance: AbstractControl, type: string): void => { - const resources = instance.get('resources').value as ResourceLwM2M[]; + const resources = deepClone(instance.get('resources').value as ResourceLwM2M[]); resources.forEach(resource => resource[type] = value); instance.get('resources').patchValue(resources); this.propagateChange(this.observeAttrTelemetryFormGroup.value); @@ -238,49 +237,54 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor } private updateInstancesIds = (data: Lwm2mObjectAddInstancesData): void => { - const instances = (this.observeAttrTelemetryFormGroup.get('clientLwM2M').value as ObjectLwM2M[]) - .find(objectLwM2M => objectLwM2M.id === data.objectId).instances; - const valueOld = this.instancesToSetId(instances); - + const objectLwM2MFormGroup = (this.observeAttrTelemetryFormGroup.get('clientLwM2M') as FormArray).controls + .find(e => e.value.id === data.objectId) as FormGroup; + const instancesArray = objectLwM2MFormGroup.value.instances as Instance []; + const instancesFormArray = objectLwM2MFormGroup.get('instances') as FormArray; + const instance0 = deepClone(instancesFormArray.at(0).value as Instance); + instance0.resources.forEach(r => { + r.attribute = false; + r.telemetry = false; + r.observe = false; + }); + const valueOld = this.instancesToSetId(instancesArray); if (!isEqual(valueOld, data.instancesIds)) { const idsDel = this.diffBetweenSet(valueOld, data.instancesIds); const idsAdd = this.diffBetweenSet(data.instancesIds, valueOld); if (idsAdd.size) { - this.addInstancesNew(data.objectId, idsAdd, instances.find(instance => instance.id === 0)); + this.addInstancesNew(idsAdd, objectLwM2MFormGroup, instancesFormArray, instance0); } if (idsDel.size) { - this.deleteInstances(data.objectId, idsDel); + this.deleteInstances(idsDel, objectLwM2MFormGroup, instancesFormArray, instance0); } } } - private deleteInstances = (objectId: number, idsDel: Set): void => { - const objectIndex = (this.observeAttrTelemetryFormGroup.get('clientLwM2M').value as ObjectLwM2M[]) - .findIndex(element => element.id === objectId); + private addInstancesNew = (idsAdd: Set, objectLwM2MFormGroup: FormGroup, instancesFormArray: FormArray, + instanceNew: Instance): void => { + idsAdd.forEach(x => { + this.pushInstance(instancesFormArray, x, instanceNew); + }); + (instancesFormArray.controls as FormGroup[]).sort((a, b) => a.value.id - b.value.id); + } + + private deleteInstances = (idsDel: Set, objectLwM2MFormGroup: FormGroup, instancesFormArray: FormArray, + instance0: Instance): void => { idsDel.forEach(x => { - const instancesFormArray = ((this.observeAttrTelemetryFormGroup.get('clientLwM2M') as FormArray) - .at(objectIndex).get('instances') as FormArray); const instanceIndex = instancesFormArray.value.findIndex(element => element.id === x); instancesFormArray.removeAt(instanceIndex); }); + if (instancesFormArray.length === 0) { + this.pushInstance(instancesFormArray, 0, instance0); + } + (instancesFormArray.controls as FormGroup[]).sort((a, b) => a.value.id - b.value.id); } - private addInstancesNew = (objectId: number, idsAdd: Set, instance: Instance): void => { - const instancesFormArray = ((this.observeAttrTelemetryFormGroup.get('clientLwM2M') as FormArray).controls - .find(e => e.value.id === objectId).get('instances') as FormArray) as FormArray; - idsAdd.forEach(x => { - const instanceNew = deepClone(instance); - instanceNew.resources.forEach(r => { - r.attribute = false; - r.telemetry = false; - r.observe = false; - }); - instancesFormArray.push(this.fb.group({ - id: x, - resources: {value: instanceNew.resources, disabled: this.disabled} - })); - }); - (instancesFormArray.controls as FormGroup[]).sort((a, b) => a.value.id - b.value.id); + private pushInstance = (instancesFormArray: FormArray, x: number, instanceNew: Instance): void => { + instancesFormArray.push(this.fb.group({ + id: x, + resources: {value: instanceNew.resources, disabled: this.disabled} + })); } private diffBetweenSet(firstSet: Set, secondSet: Set): Set { From 9b8cf75c1a5ba5ba064ad70217e9221b1a127df1 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 21 Jan 2021 18:03:36 +0200 Subject: [PATCH 055/249] UI: Refactor dashboard page. Add ability to open dashboard state in separate dialog. --- ui-ngx/src/app/core/api/widget-api.models.ts | 2 + .../dashboard/dashboard-pages.module.ts | 2 - .../dashboard-pages.routing.module.ts | 2 +- .../add-widget-dialog.component.html | 0 .../add-widget-dialog.component.ts | 0 .../dashboard-page.component.html | 8 +- .../dashboard-page.component.scss | 0 .../dashboard-page.component.ts | 19 +++-- .../dashboard-page}/dashboard-page.models.ts | 1 + .../dashboard-settings-dialog.component.html | 0 .../dashboard-settings-dialog.component.scss | 0 .../dashboard-settings-dialog.component.ts | 0 .../dashboard-toolbar.component.html | 0 .../dashboard-toolbar.component.scss | 0 .../dashboard-toolbar.component.ts | 0 .../dashboard-widget-select.component.html | 0 .../dashboard-widget-select.component.scss | 0 .../dashboard-widget-select.component.ts | 0 .../edit-widget.component.html | 0 .../dashboard-page}/edit-widget.component.ts | 0 .../layout/dashboard-layout.component.html | 0 .../layout/dashboard-layout.component.scss | 0 .../layout/dashboard-layout.component.ts | 4 +- .../dashboard-page}/layout/layout.models.ts | 0 ...ge-dashboard-layouts-dialog.component.html | 0 ...nage-dashboard-layouts-dialog.component.ts | 2 +- .../dashboard-state-dialog.component.html | 0 .../dashboard-state-dialog.component.ts | 2 +- .../default-state-controller.component.html | 0 .../default-state-controller.component.scss | 0 .../default-state-controller.component.ts | 2 +- .../entity-state-controller.component.html | 0 .../entity-state-controller.component.scss | 0 .../entity-state-controller.component.ts | 2 +- ...age-dashboard-states-dialog.component.html | 0 ...ashboard-states-dialog.component.models.ts | 0 ...age-dashboard-states-dialog.component.scss | 0 ...anage-dashboard-states-dialog.component.ts | 4 +- .../states/state-controller.component.ts | 8 +- .../states/state-controller.models.ts | 5 +- .../states/states-component.directive.ts | 16 +++- .../states/states-controller.module.ts | 4 +- .../states/states-controller.service.ts | 19 +++-- .../home/components/home-components.module.ts | 45 ++++++++++- .../widget-action-dialog.component.html | 35 ++++++++ .../action/widget-action-dialog.component.ts | 23 ++++++ .../dialog/embed-dashboard-dialog-token.ts | 22 ++++++ .../embed-dashboard-dialog.component.html | 40 ++++++++++ .../embed-dashboard-dialog.component.scss | 42 ++++++++++ .../embed-dashboard-dialog.component.ts | 79 +++++++++++++++++++ .../components/widget/widget.component.ts | 70 +++++++++++++++- .../home/pages/api-usage/api-usage.module.ts | 2 - .../pages/customer/customer-routing.module.ts | 2 +- .../dashboard/dashboard-routing.module.ts | 2 +- .../home/pages/dashboard/dashboard.module.ts | 27 +------ ui-ngx/src/app/shared/models/widget.models.ts | 5 ++ .../assets/locale/locale.constant-en_US.json | 6 ++ 57 files changed, 424 insertions(+), 78 deletions(-) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/add-widget-dialog.component.html (100%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/add-widget-dialog.component.ts (100%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/dashboard-page.component.html (97%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/dashboard-page.component.scss (100%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/dashboard-page.component.ts (98%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/dashboard-page.models.ts (99%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/dashboard-settings-dialog.component.html (100%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/dashboard-settings-dialog.component.scss (100%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/dashboard-settings-dialog.component.ts (100%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/dashboard-toolbar.component.html (100%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/dashboard-toolbar.component.scss (100%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/dashboard-toolbar.component.ts (100%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/dashboard-widget-select.component.html (100%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/dashboard-widget-select.component.scss (100%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/dashboard-widget-select.component.ts (100%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/edit-widget.component.html (100%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/edit-widget.component.ts (100%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/layout/dashboard-layout.component.html (100%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/layout/dashboard-layout.component.scss (100%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/layout/dashboard-layout.component.ts (98%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/layout/layout.models.ts (100%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/layout/manage-dashboard-layouts-dialog.component.html (100%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/layout/manage-dashboard-layouts-dialog.component.ts (98%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/states/dashboard-state-dialog.component.html (100%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/states/dashboard-state-dialog.component.ts (97%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/states/default-state-controller.component.html (100%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/states/default-state-controller.component.scss (100%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/states/default-state-controller.component.ts (98%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/states/entity-state-controller.component.html (100%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/states/entity-state-controller.component.scss (100%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/states/entity-state-controller.component.ts (98%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/states/manage-dashboard-states-dialog.component.html (100%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/states/manage-dashboard-states-dialog.component.models.ts (100%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/states/manage-dashboard-states-dialog.component.scss (100%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/states/manage-dashboard-states-dialog.component.ts (97%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/states/state-controller.component.ts (95%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/states/state-controller.models.ts (87%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/states/states-component.directive.ts (82%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/states/states-controller.module.ts (88%) rename ui-ngx/src/app/modules/home/{pages/dashboard => components/dashboard-page}/states/states-controller.service.ts (74%) create mode 100644 ui-ngx/src/app/modules/home/components/widget/dialog/embed-dashboard-dialog-token.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/dialog/embed-dashboard-dialog.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/dialog/embed-dashboard-dialog.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/widget/dialog/embed-dashboard-dialog.component.ts diff --git a/ui-ngx/src/app/core/api/widget-api.models.ts b/ui-ngx/src/app/core/api/widget-api.models.ts index b26abdb320..1579ae8d1e 100644 --- a/ui-ngx/src/app/core/api/widget-api.models.ts +++ b/ui-ngx/src/app/core/api/widget-api.models.ts @@ -53,6 +53,7 @@ import { EntityDataService } from '@core/api/entity-data.service'; import { PageData } from '@shared/models/page/page-data'; import { TranslateService } from '@ngx-translate/core'; import { AlarmDataService } from '@core/api/alarm-data.service'; +import { IDashboardController } from '@home/components/dashboard-page/dashboard-page.models'; export interface TimewindowFunctions { onUpdateTimewindow: (startTimeMs: number, endTimeMs: number, interval?: number) => void; @@ -137,6 +138,7 @@ export interface StateParams { export type StateControllerHolder = () => IStateController; export interface IStateController { + dashboardCtrl: IDashboardController; getStateParams(): StateParams; getStateParamsByStateId(stateId: string): StateParams; openState(id: string, params?: StateParams, openRightLayout?: boolean): void; diff --git a/ui-ngx/src/app/modules/dashboard/dashboard-pages.module.ts b/ui-ngx/src/app/modules/dashboard/dashboard-pages.module.ts index f09c80fea4..b7e11982f9 100644 --- a/ui-ngx/src/app/modules/dashboard/dashboard-pages.module.ts +++ b/ui-ngx/src/app/modules/dashboard/dashboard-pages.module.ts @@ -19,7 +19,6 @@ import { CommonModule } from '@angular/common'; import { SharedModule } from '@shared/shared.module'; import { HomeComponentsModule } from '@modules/home/components/home-components.module'; import { HomeDialogsModule } from '@app/modules/home/dialogs/home-dialogs.module'; -import { DashboardModule } from '@home/pages/dashboard/dashboard.module'; import { DashboardPagesRoutingModule } from './dashboard-pages.routing.module'; @NgModule({ @@ -28,7 +27,6 @@ import { DashboardPagesRoutingModule } from './dashboard-pages.routing.module'; SharedModule, HomeComponentsModule, HomeDialogsModule, - DashboardModule, DashboardPagesRoutingModule ] }) diff --git a/ui-ngx/src/app/modules/dashboard/dashboard-pages.routing.module.ts b/ui-ngx/src/app/modules/dashboard/dashboard-pages.routing.module.ts index 1354f9ef2b..2d500f1da4 100644 --- a/ui-ngx/src/app/modules/dashboard/dashboard-pages.routing.module.ts +++ b/ui-ngx/src/app/modules/dashboard/dashboard-pages.routing.module.ts @@ -18,7 +18,7 @@ import { Injectable, NgModule } from '@angular/core'; import { ActivatedRouteSnapshot, Resolve, RouterModule, Routes } from '@angular/router'; import { Authority } from '@shared/models/authority.enum'; -import { DashboardPageComponent } from '@home/pages/dashboard/dashboard-page.component'; +import { DashboardPageComponent } from '@home/components/dashboard-page/dashboard-page.component'; import { Dashboard } from '@app/shared/models/dashboard.models'; import { DashboardService } from '@core/http/dashboard.service'; import { DashboardUtilsService } from '@core/services/dashboard-utils.service'; diff --git a/ui-ngx/src/app/modules/home/pages/dashboard/add-widget-dialog.component.html b/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.html similarity index 100% rename from ui-ngx/src/app/modules/home/pages/dashboard/add-widget-dialog.component.html rename to ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.html diff --git a/ui-ngx/src/app/modules/home/pages/dashboard/add-widget-dialog.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.ts similarity index 100% rename from ui-ngx/src/app/modules/home/pages/dashboard/add-widget-dialog.component.ts rename to ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.ts diff --git a/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-page.component.html b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html similarity index 97% rename from ui-ngx/src/app/modules/home/pages/dashboard/dashboard-page.component.html rename to ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html index 5aae43bec6..97f5071955 100644 --- a/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-page.component.html +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html @@ -21,7 +21,7 @@
-
@@ -52,6 +52,7 @@ [dashboardId]="dashboard.id ? dashboard.id.id : ''" [isMobile]="isMobile" [state]="dashboardCtx.state" + [currentState]="currentState" [states]="dashboardConfiguration.states">
@@ -183,11 +184,12 @@
+ + + {{ 'widget-action.open-in-separate-dialog' | translate }} + +
+ + widget-action.dialog-title + + + + {{ 'widget-action.dialog-hide-dashboard-toolbar' | translate }} + + + widget-action.dialog-width + + + {{ 'widget-action.dialog-size-range-error' | translate }} + + + {{ 'widget-action.dialog-size-range-error' | translate }} + + + + widget-action.dialog-height + + + {{ 'widget-action.dialog-size-range-error' | translate }} + + + {{ 'widget-action.dialog-size-range-error' | translate }} + + +
+
> = + new InjectionToken>('EMBED_DASHBOARD_DIALOG_TOKEN'); + diff --git a/ui-ngx/src/app/modules/home/components/widget/dialog/embed-dashboard-dialog.component.html b/ui-ngx/src/app/modules/home/components/widget/dialog/embed-dashboard-dialog.component.html new file mode 100644 index 0000000000..04bc5708b6 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/dialog/embed-dashboard-dialog.component.html @@ -0,0 +1,40 @@ + +
+ +

{{title}}

+ + +
+ + +
+
+ +
+
+ +
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/dialog/embed-dashboard-dialog.component.scss b/ui-ngx/src/app/modules/home/components/widget/dialog/embed-dashboard-dialog.component.scss new file mode 100644 index 0000000000..b13379a744 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/dialog/embed-dashboard-dialog.component.scss @@ -0,0 +1,42 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +:host { + .dashboard-state-dialog { + .mat-dialog-content.dashboard-state-dialog-content { + max-height: 100%; + } + + @media screen and (max-width: 599px) { + width: 100% !important; + height: 100% !important; + } + + @media screen and (min-width: 600px) { + width: 480px; + height: 600px; + } + + @media screen and (min-width: 960px) { + width: 768px; + height: 600px; + } + + @media screen and (min-width: 1280px) { + width: 1000px; + height: 800px; + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/dialog/embed-dashboard-dialog.component.ts b/ui-ngx/src/app/modules/home/components/widget/dialog/embed-dashboard-dialog.component.ts new file mode 100644 index 0000000000..0d12f3c22c --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/dialog/embed-dashboard-dialog.component.ts @@ -0,0 +1,79 @@ +/// +/// Copyright © 2016-2021 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { + Component, + ComponentFactoryResolver, + Inject, + Injector, + OnInit, + ViewChild, + ViewContainerRef +} from '@angular/core'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { Router } from '@angular/router'; +import { DialogComponent } from '@shared/components/dialog.component'; +import { Dashboard } from '@shared/models/dashboard.models'; + +export interface EmbedDashboardDialogData { + dashboard: Dashboard; + state: string; + title: string; + hideToolbar: boolean; + width?: number; + height?: number; +} + +@Component({ + selector: 'tb-embed-dashboard-dialog', + templateUrl: './embed-dashboard-dialog.component.html', + styleUrls: ['./embed-dashboard-dialog.component.scss'] +}) +export class EmbedDashboardDialogComponent extends DialogComponent + implements OnInit { + + @ViewChild('dashboardContent', {read: ViewContainerRef, static: true}) dashboardContentContainer: ViewContainerRef; + + dashboard = this.data.dashboard; + state = this.data.state; + title = this.data.title; + hideToolbar = this.data.hideToolbar; + + dialogStyle: any = {}; + + constructor(protected store: Store, + protected router: Router, + @Inject(MAT_DIALOG_DATA) public data: EmbedDashboardDialogData, + public dialogRef: MatDialogRef) { + super(store, router, dialogRef); + if (this.data.width) { + this.dialogStyle.width = this.data.width + 'vw'; + } + if (this.data.height) { + this.dialogStyle.height = this.data.height + 'vh'; + } + } + + ngOnInit(): void { + } + + close(): void { + this.dialogRef.close(null); + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts index ef5555e5eb..e780bbfedf 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts @@ -22,6 +22,7 @@ import { ComponentFactoryResolver, ComponentRef, ElementRef, + Inject, Injector, Input, NgZone, @@ -54,7 +55,7 @@ import { AppState } from '@core/core.state'; import { WidgetService } from '@core/http/widget.service'; import { UtilsService } from '@core/services/utils.service'; import { forkJoin, Observable, of, ReplaySubject, Subscription, throwError } from 'rxjs'; -import { deepClone, isDefined, objToBase64URI } from '@core/utils'; +import { deepClone, insertVariable, isDefined, objToBase64, objToBase64URI } from '@core/utils'; import { IDynamicWidgetComponent, WidgetContext, @@ -93,6 +94,10 @@ import { EntityDataService } from '@core/api/entity-data.service'; import { TranslateService } from '@ngx-translate/core'; import { NotificationType } from '@core/notification/notification.models'; import { AlarmDataService } from '@core/api/alarm-data.service'; +import { MatDialog } from '@angular/material/dialog'; +import { ComponentType } from '@angular/cdk/portal'; +import { EMBED_DASHBOARD_DIALOG_TOKEN } from '@home/components/widget/dialog/embed-dashboard-dialog-token'; +import { Dashboard } from '@shared/models/dashboard.models'; @Component({ selector: 'tb-widget', @@ -161,6 +166,8 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI private componentFactoryResolver: ComponentFactoryResolver, private elementRef: ElementRef, private injector: Injector, + private dialog: MatDialog, + @Inject(EMBED_DASHBOARD_DIALOG_TOKEN) private embedDashboardDialogComponent: ComponentType, private widgetService: WidgetService, private resources: ResourcesService, private timeService: TimeService, @@ -1007,7 +1014,11 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI const params = deepClone(this.widgetContext.stateController.getStateParams()); this.updateEntityParams(params, targetEntityParamName, targetEntityId, entityName, entityLabel); if (type === WidgetActionType.openDashboardState) { - this.widgetContext.stateController.openState(targetDashboardStateId, params, descriptor.openRightLayout); + if (descriptor.openInSeparateDialog) { + this.openDashboardStateInDialog(descriptor, entityId, entityName, additionalParams, entityLabel); + } else { + this.widgetContext.stateController.openState(targetDashboardStateId, params, descriptor.openRightLayout); + } } else { this.widgetContext.stateController.updateState(targetDashboardStateId, params, descriptor.openRightLayout); } @@ -1083,6 +1094,61 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI } } + private openDashboardStateInDialog(descriptor: WidgetActionDescriptor, + entityId?: EntityId, entityName?: string, additionalParams?: any, entityLabel?: string) { + const dashboard = deepClone(this.widgetContext.stateController.dashboardCtrl.dashboardCtx.getDashboard()); + const stateObject: StateObject = {}; + stateObject.params = {}; + const targetEntityParamName = descriptor.stateEntityParamName; + const targetDashboardStateId = descriptor.targetDashboardStateId; + let targetEntityId: EntityId; + if (descriptor.setEntityId) { + targetEntityId = entityId; + } + this.updateEntityParams(stateObject.params, targetEntityParamName, targetEntityId, entityName, entityLabel); + if (targetDashboardStateId) { + stateObject.id = targetDashboardStateId; + } + let title = descriptor.dialogTitle; + if (!title) { + if (targetDashboardStateId && dashboard.configuration.states) { + const dashboardState = dashboard.configuration.states[targetDashboardStateId]; + if (dashboardState) { + title = dashboardState.name; + } + } + } + if (!title) { + title = dashboard.title; + } + title = this.utils.customTranslation(title, title); + const params = stateObject.params; + const paramsEntityName = params && params.entityName ? params.entityName : ''; + const paramsEntityLabel = params && params.entityLabel ? params.entityLabel : ''; + title = insertVariable(title, 'entityName', paramsEntityName); + title = insertVariable(title, 'entityLabel', paramsEntityLabel); + for (const prop of Object.keys(params)) { + if (params[prop] && params[prop].entityName) { + title = insertVariable(title, prop + ':entityName', params[prop].entityName); + } + if (params[prop] && params[prop].entityLabel) { + title = insertVariable(title, prop + ':entityLabel', params[prop].entityLabel); + } + } + this.dialog.open(this.embedDashboardDialogComponent, { + disableClose: true, + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], + data: { + dashboard, + state: objToBase64([ stateObject ]), + title, + hideToolbar: descriptor.dialogHideDashboardToolbar, + width: descriptor.dialogWidth, + height: descriptor.dialogHeight + } + }); + } + private elementClick($event: Event) { const e = ($event.target || $event.srcElement) as Element; if (e.id) { diff --git a/ui-ngx/src/app/modules/home/pages/api-usage/api-usage.module.ts b/ui-ngx/src/app/modules/home/pages/api-usage/api-usage.module.ts index a95b396d92..47bf4bd0d2 100644 --- a/ui-ngx/src/app/modules/home/pages/api-usage/api-usage.module.ts +++ b/ui-ngx/src/app/modules/home/pages/api-usage/api-usage.module.ts @@ -19,7 +19,6 @@ import { CommonModule } from '@angular/common'; import { SharedModule } from '@app/shared/shared.module'; import { HomeComponentsModule } from '@modules/home/components/home-components.module'; import { ApiUsageComponent } from '@home/pages/api-usage/api-usage.component'; -import { DashboardModule } from '@home/pages/dashboard/dashboard.module'; import { ApiUsageRoutingModule } from '@home/pages/api-usage/api-usage-routing.module'; @NgModule({ @@ -31,7 +30,6 @@ import { ApiUsageRoutingModule } from '@home/pages/api-usage/api-usage-routing.m CommonModule, SharedModule, HomeComponentsModule, - DashboardModule, ApiUsageRoutingModule ] }) diff --git a/ui-ngx/src/app/modules/home/pages/customer/customer-routing.module.ts b/ui-ngx/src/app/modules/home/pages/customer/customer-routing.module.ts index 166efa46e2..2807baae04 100644 --- a/ui-ngx/src/app/modules/home/pages/customer/customer-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/customer/customer-routing.module.ts @@ -24,7 +24,7 @@ import { CustomersTableConfigResolver } from './customers-table-config.resolver' import { DevicesTableConfigResolver } from '@modules/home/pages/device/devices-table-config.resolver'; import { AssetsTableConfigResolver } from '../asset/assets-table-config.resolver'; import { DashboardsTableConfigResolver } from '@modules/home/pages/dashboard/dashboards-table-config.resolver'; -import { DashboardPageComponent } from '@home/pages/dashboard/dashboard-page.component'; +import { DashboardPageComponent } from '@home/components/dashboard-page/dashboard-page.component'; import { BreadCrumbConfig } from '@shared/components/breadcrumb'; import { dashboardBreadcumbLabelFunction, DashboardResolver } from '@home/pages/dashboard/dashboard-routing.module'; diff --git a/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-routing.module.ts b/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-routing.module.ts index 7cf02aea32..55c1fc0d28 100644 --- a/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-routing.module.ts @@ -20,7 +20,7 @@ import { ActivatedRouteSnapshot, Resolve, RouterModule, Routes } from '@angular/ import { EntitiesTableComponent } from '../../components/entity/entities-table.component'; import { Authority } from '@shared/models/authority.enum'; import { DashboardsTableConfigResolver } from './dashboards-table-config.resolver'; -import { DashboardPageComponent } from '@home/pages/dashboard/dashboard-page.component'; +import { DashboardPageComponent } from '@home/components/dashboard-page/dashboard-page.component'; import { BreadCrumbConfig, BreadCrumbLabelFunction } from '@shared/components/breadcrumb'; import { Observable } from 'rxjs'; import { Dashboard } from '@app/shared/models/dashboard.models'; diff --git a/ui-ngx/src/app/modules/home/pages/dashboard/dashboard.module.ts b/ui-ngx/src/app/modules/home/pages/dashboard/dashboard.module.ts index 9b4e8690d7..0c1e7887f0 100644 --- a/ui-ngx/src/app/modules/home/pages/dashboard/dashboard.module.ts +++ b/ui-ngx/src/app/modules/home/pages/dashboard/dashboard.module.ts @@ -24,44 +24,19 @@ import { DashboardRoutingModule } from './dashboard-routing.module'; import { MakeDashboardPublicDialogComponent } from '@modules/home/pages/dashboard/make-dashboard-public-dialog.component'; import { HomeComponentsModule } from '@modules/home/components/home-components.module'; import { DashboardTabsComponent } from '@home/pages/dashboard/dashboard-tabs.component'; -import { DashboardPageComponent } from '@home/pages/dashboard/dashboard-page.component'; -import { DashboardToolbarComponent } from './dashboard-toolbar.component'; -import { StatesControllerModule } from '@home/pages/dashboard/states/states-controller.module'; -import { DashboardLayoutComponent } from './layout/dashboard-layout.component'; -import { EditWidgetComponent } from './edit-widget.component'; -import { DashboardWidgetSelectComponent } from './dashboard-widget-select.component'; -import { AddWidgetDialogComponent } from './add-widget-dialog.component'; -import { ManageDashboardLayoutsDialogComponent } from './layout/manage-dashboard-layouts-dialog.component'; -import { DashboardSettingsDialogComponent } from './dashboard-settings-dialog.component'; -import { ManageDashboardStatesDialogComponent } from './states/manage-dashboard-states-dialog.component'; -import { DashboardStateDialogComponent } from './states/dashboard-state-dialog.component'; @NgModule({ declarations: [ DashboardFormComponent, DashboardTabsComponent, ManageDashboardCustomersDialogComponent, - MakeDashboardPublicDialogComponent, - DashboardToolbarComponent, - DashboardPageComponent, - DashboardLayoutComponent, - EditWidgetComponent, - DashboardWidgetSelectComponent, - AddWidgetDialogComponent, - ManageDashboardLayoutsDialogComponent, - DashboardSettingsDialogComponent, - ManageDashboardStatesDialogComponent, - DashboardStateDialogComponent - ], - exports: [ - DashboardPageComponent + MakeDashboardPublicDialogComponent ], imports: [ CommonModule, SharedModule, HomeComponentsModule, HomeDialogsModule, - StatesControllerModule, DashboardRoutingModule ] }) diff --git a/ui-ngx/src/app/shared/models/widget.models.ts b/ui-ngx/src/app/shared/models/widget.models.ts index 24ea528b46..179a6ff47b 100644 --- a/ui-ngx/src/app/shared/models/widget.models.ts +++ b/ui-ngx/src/app/shared/models/widget.models.ts @@ -345,6 +345,11 @@ export interface WidgetActionDescriptor extends CustomActionDescriptor { targetDashboardStateId?: string; openRightLayout?: boolean; openNewBrowserTab?: boolean; + openInSeparateDialog?: boolean; + dialogTitle?: string; + dialogHideDashboardToolbar?: boolean; + dialogWidth?: number; + dialogHeight?: number; setEntityId?: boolean; stateEntityParamName?: string; } diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 5ebc491c49..a099baaeb3 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -2258,6 +2258,12 @@ "set-entity-from-widget": "Set entity from widget", "target-dashboard": "Target dashboard", "open-right-layout": "Open right dashboard layout (mobile view)", + "open-in-separate-dialog": "Open in separate dialog", + "dialog-title": "Dialog title", + "dialog-hide-dashboard-toolbar": "Hide dashboard toolbar in dialog", + "dialog-width": "Dialog width in percents relative to viewport width", + "dialog-height": "Dialog height in percents relative to viewport height", + "dialog-size-range-error": "Dialog size percent value should be in a range from 1 to 100.", "open-new-browser-tab": "Open in a new browser tab" }, "widgets-bundle": { From 15abe85b748eb6e08945faff865f92fd517a56ce Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Thu, 21 Jan 2021 18:21:55 +0200 Subject: [PATCH 056/249] UI: Refactoring LwM2M --- ...ofile-transport-configuration.component.ts | 15 +++--- .../lwm2m/security-config-server.component.ts | 18 ++++---- .../device/lwm2m/security-config.component.ts | 46 +++++++++---------- 3 files changed, 38 insertions(+), 41 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts index 5ce7620e32..1711f11ade 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts @@ -73,8 +73,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro this.requiredValue = coerceBooleanProperty(value); } - private propagateChange = (v: any) => { - }; + private propagateChange = (v: any) => { }; constructor(private store: Store, private fb: FormBuilder, @@ -141,7 +140,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } private updateWriteValue = (value: any): void => { - const objectsList = deepClone(value.objectsList); + const objectsList = value.objectsList; this.lwm2mDeviceProfileTransportConfFormGroup.patchValue({ objectIds: value, observeAttrTelemetry: {clientLwM2M: this.getObserveAttrTelemetryObjects(objectsList)}, @@ -251,12 +250,12 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } private getObserveAttrTelemetryObjects = (listObject: ObjectLwM2M[]): ObjectLwM2M [] => { - const clientObserveAttr = deepClone(listObject); + const clientObserveAttr = listObject; if (this.configurationValue[this.observeAttr]) { - const observeArray = this.configurationValue[this.observeAttr][this.observe] as Array; - const attributeArray = this.configurationValue[this.observeAttr][this.attribute] as Array; - const telemetryArray = this.configurationValue[this.observeAttr][this.telemetry] as Array; - const keyNameJson = this.configurationValue[this.observeAttr][this.keyName] as JsonObject; + const observeArray = this.configurationValue[this.observeAttr][this.observe]; + const attributeArray = this.configurationValue[this.observeAttr][this.attribute]; + const telemetryArray = this.configurationValue[this.observeAttr][this.telemetry]; + const keyNameJson = this.configurationValue[this.observeAttr][this.keyName]; if (this.includesInstancesNo(attributeArray, telemetryArray)) { this.addInstances(attributeArray, telemetryArray, clientObserveAttr); } diff --git a/ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config-server.component.ts b/ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config-server.component.ts index b9e1ddf6b0..d88115e266 100644 --- a/ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config-server.component.ts +++ b/ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config-server.component.ts @@ -15,19 +15,17 @@ /// import { Component, forwardRef, Inject, Input, OnInit } from '@angular/core'; - -import { - ControlValueAccessor, - FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators -} from '@angular/forms'; +import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; import { - SECURITY_CONFIG_MODE, - SECURITY_CONFIG_MODE_NAMES, - KEY_REGEXP_HEX_DEC, - ServerSecurityConfig, DeviceCredentialsDialogLwm2mData, + KEY_REGEXP_HEX_DEC, + LEN_MAX_PRIVATE_KEY, LEN_MAX_PSK, - LEN_MAX_PRIVATE_KEY, LEN_MAX_PUBLIC_KEY_RPK, LEN_MAX_PUBLIC_KEY_X509 + LEN_MAX_PUBLIC_KEY_RPK, + LEN_MAX_PUBLIC_KEY_X509, + SECURITY_CONFIG_MODE, + SECURITY_CONFIG_MODE_NAMES, + ServerSecurityConfig } from '@home/pages/device/lwm2m/security-config.models'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; diff --git a/ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config.component.ts b/ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config.component.ts index 3fcd0ae01d..32e1f0736f 100644 --- a/ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config.component.ts +++ b/ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config.component.ts @@ -15,7 +15,7 @@ /// -import {Component, Inject, OnInit } from '@angular/core'; +import { Component, Inject, OnInit } from '@angular/core'; import { DialogComponent } from '@shared/components/dialog.component'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; @@ -24,22 +24,22 @@ import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { TranslateService } from '@ngx-translate/core'; import { - SECURITY_CONFIG_MODE_NAMES, - SECURITY_CONFIG_MODE, - SecurityConfigModels, - ClientSecurityConfigPSK, - ClientSecurityConfigRPK, - JSON_ALL_CONFIG, - KEY_REGEXP_HEX_DEC, - DeviceCredentialsDialogLwm2mData, BOOTSTRAP_SERVER, BOOTSTRAP_SERVERS, - LWM2M_SERVER, - ClientSecurityConfigX509, ClientSecurityConfigNoSEC, + ClientSecurityConfigPSK, + ClientSecurityConfigRPK, + ClientSecurityConfigX509, + DeviceCredentialsDialogLwm2mData, getDefaultClientSecurityConfigType, + JSON_ALL_CONFIG, + KEY_REGEXP_HEX_DEC, LEN_MAX_PSK, - LEN_MAX_PUBLIC_KEY_RPK + LEN_MAX_PUBLIC_KEY_RPK, + LWM2M_SERVER, + SECURITY_CONFIG_MODE, + SECURITY_CONFIG_MODE_NAMES, + SecurityConfigModels } from './security-config.models'; import { WINDOW } from '@core/services/window.service'; import { MatTabChangeEvent } from '@angular/material/tabs'; @@ -65,9 +65,9 @@ export class SecurityConfigComponent extends DialogComponent, protected router: Router, @@ -111,23 +111,23 @@ export class SecurityConfigComponent extends DialogComponent { - switch (jsonAllConfig.client.securityConfigClientMode.toString()) { - case SECURITY_CONFIG_MODE.NO_SEC.toString(): + switch (jsonAllConfig.client.securityConfigClientMode) { + case SECURITY_CONFIG_MODE.NO_SEC: break; - case SECURITY_CONFIG_MODE.PSK.toString(): + case SECURITY_CONFIG_MODE.PSK: const clientSecurityConfigPSK = jsonAllConfig.client as ClientSecurityConfigPSK; this.lwm2mConfigFormGroup.patchValue({ identityPSK: clientSecurityConfigPSK.identity, clientKey: clientSecurityConfigPSK.key, }, {emitEvent: false}); break; - case SECURITY_CONFIG_MODE.RPK.toString(): + case SECURITY_CONFIG_MODE.RPK: const clientSecurityConfigRPK = jsonAllConfig.client as ClientSecurityConfigRPK; this.lwm2mConfigFormGroup.patchValue({ clientKey: clientSecurityConfigRPK.key, }, {emitEvent: false}); break; - case SECURITY_CONFIG_MODE.X509.toString(): + case SECURITY_CONFIG_MODE.X509: const clientSecurityConfigX509 = jsonAllConfig.client as ClientSecurityConfigX509; this.lwm2mConfigFormGroup.patchValue({ clientCertificate: clientSecurityConfigX509.x509 @@ -295,7 +295,7 @@ export class SecurityConfigComponent extends DialogComponent { const securityMode = 'securityMode'; - if (this.lwm2mConfigFormGroup.get('bootstrapServer').value[securityMode] === SECURITY_CONFIG_MODE.PSK.toString()) { + if (this.lwm2mConfigFormGroup.get('bootstrapServer').value[securityMode] === SECURITY_CONFIG_MODE.PSK) { this.lwm2mConfigFormGroup.get('bootstrapFormGroup').patchValue({ clientPublicKeyOrId: this.lwm2mConfigFormGroup.get('identityPSK').value }); @@ -303,7 +303,7 @@ export class SecurityConfigComponent extends DialogComponent Date: Fri, 22 Jan 2021 11:53:00 +0200 Subject: [PATCH 057/249] Moved code to existing processing --- .../service/DefaultTransportService.java | 46 +++++-------------- 1 file changed, 12 insertions(+), 34 deletions(-) diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java index 86b49f4915..7ff81610b1 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java @@ -647,37 +647,7 @@ public class DefaultTransportService implements TransportService { } } else if (EntityType.DEVICE.equals(entityType)) { Optional deviceOpt = dataDecodingEncodingService.decode(msg.getData().toByteArray()); - if (deviceOpt.isPresent()) { - Device device = deviceOpt.get(); - if (device.getAdditionalInfo().has("gateway") && device.getAdditionalInfo().get("gateway").asBoolean()) { - sessions.forEach((uuid, currentMD) -> { - if (device.getId().equals(new DeviceId(new UUID(currentMD.getSessionInfo().getDeviceIdMSB(), currentMD.getSessionInfo().getDeviceIdLSB())))) { - boolean newActivityTimeFromGatewayDevice = device.getAdditionalInfo().get("activityTimeFromGatewayDevice").asBoolean(); - if (currentMD.getSessionInfo().getActivityTimeFromGatewayDevice() != newActivityTimeFromGatewayDevice) { - SessionInfoProto currentSessionInfo = currentMD.getSessionInfo(); - SessionInfoProto newSessionInfo = SessionInfoProto.newBuilder() - .setNodeId(currentSessionInfo.getNodeId()) - .setSessionIdMSB(currentSessionInfo.getSessionIdMSB()) - .setSessionIdLSB(currentSessionInfo.getSessionIdLSB()) - .setDeviceIdMSB(currentSessionInfo.getDeviceIdMSB()) - .setDeviceIdLSB(currentSessionInfo.getDeviceIdLSB()) - .setTenantIdMSB(currentSessionInfo.getTenantIdMSB()) - .setTenantIdLSB(currentSessionInfo.getTenantIdLSB()) - .setDeviceName(currentSessionInfo.getDeviceName()) - .setDeviceType(currentSessionInfo.getDeviceType()) - .setGwSessionIdMSB(currentSessionInfo.getGwSessionIdMSB()) - .setGwSessionIdLSB(currentSessionInfo.getGwSessionIdLSB()) - .setDeviceProfileIdMSB(currentSessionInfo.getDeviceProfileIdMSB()) - .setDeviceProfileIdLSB(currentSessionInfo.getDeviceProfileIdLSB()) - .setActivityTimeFromGatewayDevice(newActivityTimeFromGatewayDevice) - .build(); - currentMD.setSessionInfo(newSessionInfo); - } - } - }); - } - onDeviceUpdate(device); - } + deviceOpt.ifPresent(this::onDeviceUpdate); } } else if (toSessionMsg.hasEntityDeleteMsg()) { TransportProtos.EntityDeleteMsg msg = toSessionMsg.getEntityDeleteMsg(); @@ -733,13 +703,21 @@ public class DefaultTransportService implements TransportService { } else { newDeviceProfile = null; } - TransportProtos.SessionInfoProto newSessionInfo = TransportProtos.SessionInfoProto.newBuilder() + TransportProtos.SessionInfoProto.Builder newSessionInfoBuilder = TransportProtos.SessionInfoProto.newBuilder() .mergeFrom(md.getSessionInfo()) .setDeviceProfileIdMSB(deviceProfileIdMSB) .setDeviceProfileIdLSB(deviceProfileIdLSB) .setDeviceName(device.getName()) - .setDeviceType(device.getType()) - .build(); + .setDeviceType(device.getType()); + if (device.getAdditionalInfo().has("gateway") + && device.getAdditionalInfo().get("gateway").asBoolean() + && device.getAdditionalInfo().has("activityTimeFromGatewayDevice")) { + boolean activityTimeFromGatewayDevice = device.getAdditionalInfo().get("activityTimeFromGatewayDevice").asBoolean(); + if (md.getSessionInfo().getActivityTimeFromGatewayDevice() != activityTimeFromGatewayDevice) { + newSessionInfoBuilder.setActivityTimeFromGatewayDevice(activityTimeFromGatewayDevice); + } + } + TransportProtos.SessionInfoProto newSessionInfo = newSessionInfoBuilder.build(); md.setSessionInfo(newSessionInfo); transportCallbackExecutor.submit(() -> md.getListener().onDeviceUpdate(newSessionInfo, device, Optional.ofNullable(newDeviceProfile))); } From ddb01aac1769867a2e2c20d7ab93b3013ac4246e Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Fri, 22 Jan 2021 12:30:40 +0200 Subject: [PATCH 058/249] Minor fixes --- .../src/app/modules/dashboard/dashboard-pages.routing.module.ts | 1 + .../src/app/modules/home/components/widget/widget.component.ts | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/dashboard/dashboard-pages.routing.module.ts b/ui-ngx/src/app/modules/dashboard/dashboard-pages.routing.module.ts index 2d500f1da4..5c3bcb8d11 100644 --- a/ui-ngx/src/app/modules/dashboard/dashboard-pages.routing.module.ts +++ b/ui-ngx/src/app/modules/dashboard/dashboard-pages.routing.module.ts @@ -95,6 +95,7 @@ const routes: Routes = [ exports: [RouterModule], providers: [ WidgetEditorDashboardResolver, + DashboardResolver, { provide: MODULES_MAP, useValue: modulesMap diff --git a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts index e780bbfedf..7838f7e7ba 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts @@ -97,7 +97,6 @@ import { AlarmDataService } from '@core/api/alarm-data.service'; import { MatDialog } from '@angular/material/dialog'; import { ComponentType } from '@angular/cdk/portal'; import { EMBED_DASHBOARD_DIALOG_TOKEN } from '@home/components/widget/dialog/embed-dashboard-dialog-token'; -import { Dashboard } from '@shared/models/dashboard.models'; @Component({ selector: 'tb-widget', From fa8df682070d40e9630b3e621a454d98af195dc3 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Fri, 22 Jan 2021 14:46:55 +0200 Subject: [PATCH 059/249] Lwm2m: front: refactoring5 --- .../controller/DeviceLwm2mController.java | 10 +- .../service/lwm2m/LwM2MModelsRepository.java | 323 ++++++++++-------- .../server/common/data/lwm2m/LwM2mObject.java | 4 + .../app/core/http/device-profile.service.ts | 14 +- ...ofile-transport-configuration.component.ts | 7 +- 5 files changed, 207 insertions(+), 151 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceLwm2mController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceLwm2mController.java index c38a163af9..a12bfb8900 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceLwm2mController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceLwm2mController.java @@ -48,13 +48,15 @@ import java.util.Map; @RequestMapping("/api") public class DeviceLwm2mController extends BaseController { - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") - @RequestMapping(value = "/lwm2m/deviceProfile/{objectIds}", method = RequestMethod.GET) + @RequestMapping(value = "/lwm2m/deviceProfile", params = {"objectIds"}, method = RequestMethod.GET) @ResponseBody - public List getLwm2mListObjects(@PathVariable("objectIds") int[] objectIds) throws ThingsboardException { + public List getLwm2mListObjects(@RequestParam int[] objectIds, + @RequestParam(required = false) String textSearch, + @RequestParam(required = false) String sortProperty, + @RequestParam(required = false) String sortOrder) throws ThingsboardException { try { - return lwM2MModelsRepository.getLwm2mObjects(objectIds, null); + return lwM2MModelsRepository.getLwm2mObjects(objectIds, textSearch, sortProperty, sortOrder); } catch (Exception e) { throw handleException(e); } diff --git a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MModelsRepository.java b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MModelsRepository.java index cea898e7a1..4057d613b9 100644 --- a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MModelsRepository.java +++ b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MModelsRepository.java @@ -23,8 +23,11 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.data.domain.PageImpl; import org.springframework.stereotype.Service; -import org.thingsboard.server.common.data.lwm2m.*; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.lwm2m.LwM2mInstance; +import org.thingsboard.server.common.data.lwm2m.LwM2mObject; +import org.thingsboard.server.common.data.lwm2m.LwM2mResource; +import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.transport.lwm2m.LwM2MTransportConfigBootstrap; @@ -32,17 +35,23 @@ import org.thingsboard.server.common.transport.lwm2m.LwM2MTransportConfigServer; import org.thingsboard.server.dao.service.Validator; import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode; +import java.lang.reflect.Field; import java.math.BigInteger; -import java.security.*; +import java.security.AlgorithmParameters; +import java.security.GeneralSecurityException; +import java.security.KeyFactory; +import java.security.KeyStoreException; +import java.security.PublicKey; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; import java.security.spec.ECGenParameterSpec; import java.security.spec.ECParameterSpec; -import java.security.spec.ECPublicKeySpec; import java.security.spec.ECPoint; +import java.security.spec.ECPublicKeySpec; import java.security.spec.KeySpec; -import java.util.List; import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -70,22 +79,26 @@ public class LwM2MModelsRepository { * Filter by Predicate (uses objectIds, if objectIds is null then it uses textSearch, * if textSearch is null then it uses AllList from List) */ - public List getLwm2mObjects(int[] objectIds, String textSearch) { - return getLwm2mObjects((objectIds != null && objectIds.length > 0) ? - (ObjectModel element) -> IntStream.of(objectIds).anyMatch(x -> x == element.id) : - (textSearch != null && !textSearch.isEmpty()) ? (ObjectModel element) -> element.name.contains(textSearch) : null); + public List getLwm2mObjects(int[] objectIds, String textSearch, String sortProperty, String sortOrder) { + return getLwm2mObjects((objectIds != null && objectIds.length > 0 && textSearch != null && !textSearch.isEmpty()) ? + (ObjectModel element) -> IntStream.of(objectIds).anyMatch(x -> x == element.id) || element.name.contains(textSearch) : + (objectIds != null && objectIds.length > 0) ? + (ObjectModel element) -> IntStream.of(objectIds).anyMatch(x -> x == element.id) : + (textSearch != null && !textSearch.isEmpty()) ? (ObjectModel element) -> element.name.contains(textSearch) : null, + sortProperty, sortOrder); } /** * @param predicate * @return list of LwM2mObject */ - private List getLwm2mObjects(Predicate predicate) { + private List getLwm2mObjects(Predicate predicate, String sortProperty, String sortOrder) { List lwM2mObjects = new ArrayList<>(); List listObjects = (predicate == null) ? this.contextServer.getModelsValue() : contextServer.getModelsValue().stream() .filter(predicate) .collect(Collectors.toList()); + listObjects.forEach(obj -> { LwM2mObject lwM2mObject = new LwM2mObject(); lwM2mObject.setId(obj.id); @@ -105,153 +118,177 @@ public class LwM2MModelsRepository { lwM2mObject.setInstances(new LwM2mInstance[]{instance}); lwM2mObjects.add(lwM2mObject); }); + try { + Field field = LwM2mObject.class.getField(sortProperty); + } catch (NoSuchFieldException e) { + e.printStackTrace(); + } + switch (sortProperty) { + case "name": + switch (sortOrder) { + case "ASC": + // ASC + lwM2mObjects.sort((o1, o2) -> o1.getName().compareTo(o2.getName())); + break; + case "DESC": + // DESC + lwM2mObjects.stream().sorted(Comparator.comparing(LwM2mObject::getName).reversed()); + break; + } + case "id": + switch (sortOrder) { + case "ASC": + // ASC + lwM2mObjects.sort((o1, o2) -> Long.compare(o1.getId(), o2.getId())); + break; + case "DESC": + // DESC + lwM2mObjects.sort((o1, o2) -> Long.compare(o2.getId(), o1.getId())); + } + } return lwM2mObjects; } - /** - * @param tenantId - * @param pageLink - * @return List of LwM2mObject in PageData format - */ - public PageData findDeviceLwm2mObjects(TenantId tenantId, PageLink pageLink) { - log.trace("Executing findDeviceProfileInfos tenantId [{}], pageLink [{}]", tenantId, pageLink); - validateId(tenantId, INCORRECT_TENANT_ID + tenantId); - Validator.validatePageLink(pageLink); - return this.findLwm2mListObjects(pageLink); - } + /** + * @param tenantId + * @param pageLink + * @return List of LwM2mObject in PageData format + */ + public PageData findDeviceLwm2mObjects (TenantId tenantId, PageLink pageLink){ + log.trace("Executing findDeviceProfileInfos tenantId [{}], pageLink [{}]", tenantId, pageLink); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + Validator.validatePageLink(pageLink); + return this.findLwm2mListObjects(pageLink); + } - /** - * @param pageLink - * @return List of LwM2mObject in PageData format, filter == TextSearch - * PageNumber = 1, PageSize = List.size() - */ - public PageData findLwm2mListObjects(PageLink pageLink) { - PageImpl page = new PageImpl(getLwm2mObjects(null, pageLink.getTextSearch())); - PageData pageData = new PageData(page.getContent(), page.getTotalPages(), page.getTotalElements(), page.hasNext()); - return pageData; - } + /** + * @param pageLink + * @return List of LwM2mObject in PageData format, filter == TextSearch + * PageNumber = 1, PageSize = List.size() + */ + public PageData findLwm2mListObjects (PageLink pageLink){ + PageImpl page = new PageImpl(getLwm2mObjects(null, pageLink.getTextSearch(), pageLink.getSortOrder().getProperty(), pageLink.getSortOrder().getDirection().name())); + PageData pageData = new PageData(page.getContent(), page.getTotalPages(), page.getTotalElements(), page.hasNext()); + return pageData; + } - /** - * - * @param securityMode - * @param bootstrapServerIs - * @return ServerSecurityConfig more value is default: Important - port, host, publicKey - */ - public ServerSecurityConfig getBootstrapSecurityInfo(String securityMode, boolean bootstrapServerIs) { - LwM2MSecurityMode lwM2MSecurityMode = LwM2MSecurityMode.fromSecurityMode(securityMode.toLowerCase()); - return getBootstrapServer(bootstrapServerIs, lwM2MSecurityMode); - } + /** + * @param securityMode + * @param bootstrapServerIs + * @return ServerSecurityConfig more value is default: Important - port, host, publicKey + */ + public ServerSecurityConfig getBootstrapSecurityInfo (String securityMode,boolean bootstrapServerIs){ + LwM2MSecurityMode lwM2MSecurityMode = LwM2MSecurityMode.fromSecurityMode(securityMode.toLowerCase()); + return getBootstrapServer(bootstrapServerIs, lwM2MSecurityMode); + } - /** - * - * @param bootstrapServerIs - * @param mode - * @return ServerSecurityConfig more value is default: Important - port, host, publicKey - */ - private ServerSecurityConfig getBootstrapServer(boolean bootstrapServerIs, LwM2MSecurityMode mode) { - ServerSecurityConfig bsServ = new ServerSecurityConfig(); - bsServ.setBootstrapServerIs(bootstrapServerIs); - if (bootstrapServerIs) { - bsServ.setServerId(contextBootStrap.getBootstrapServerId()); - switch (mode) { - case NO_SEC: - bsServ.setHost(contextBootStrap.getBootstrapHost()); - bsServ.setPort(contextBootStrap.getBootstrapPortNoSecPsk()); - bsServ.setServerPublicKey(""); - break; - case PSK: - bsServ.setHost(contextBootStrap.getBootstrapSecureHost()); - bsServ.setPort(contextBootStrap.getBootstrapSecurePortPsk()); - bsServ.setServerPublicKey(""); - break; - case RPK: - bsServ.setHost(contextBootStrap.getBootstrapSecureHost()); - bsServ.setPort(contextBootStrap.getBootstrapSecurePortRpk()); - bsServ.setServerPublicKey(getRPKPublicKey(this.contextBootStrap.getBootstrapPublicX(), this.contextBootStrap.getBootstrapPublicY())); - break; - case X509: - bsServ.setHost(contextBootStrap.getBootstrapSecureHost()); - bsServ.setPort(contextBootStrap.getBootstrapSecurePortX509()); - bsServ.setServerPublicKey(getServerPublicKeyX509(contextBootStrap.getBootstrapAlias())); - break; - default: - break; - } - } else { - bsServ.setServerId(contextServer.getServerId()); - switch (mode) { - case NO_SEC: - bsServ.setHost(contextServer.getServerHost()); - bsServ.setPort(contextServer.getServerPortNoSecPsk()); - bsServ.setServerPublicKey(""); - break; - case PSK: - bsServ.setHost(contextServer.getServerSecureHost()); - bsServ.setPort(contextServer.getServerPortPsk()); - bsServ.setServerPublicKey(""); - break; - case RPK: - bsServ.setHost(contextServer.getServerSecureHost()); - bsServ.setPort(contextServer.getServerPortRpk()); - bsServ.setServerPublicKey(getRPKPublicKey(this.contextServer.getServerPublicX(), this.contextServer.getServerPublicY())); - break; - case X509: - bsServ.setHost(contextServer.getServerSecureHost()); - bsServ.setPort(contextServer.getServerPortX509()); - bsServ.setServerPublicKey(getServerPublicKeyX509(contextServer.getServerAlias())); - break; - default: - break; + /** + * @param bootstrapServerIs + * @param mode + * @return ServerSecurityConfig more value is default: Important - port, host, publicKey + */ + private ServerSecurityConfig getBootstrapServer ( boolean bootstrapServerIs, LwM2MSecurityMode mode){ + ServerSecurityConfig bsServ = new ServerSecurityConfig(); + bsServ.setBootstrapServerIs(bootstrapServerIs); + if (bootstrapServerIs) { + bsServ.setServerId(contextBootStrap.getBootstrapServerId()); + switch (mode) { + case NO_SEC: + bsServ.setHost(contextBootStrap.getBootstrapHost()); + bsServ.setPort(contextBootStrap.getBootstrapPortNoSecPsk()); + bsServ.setServerPublicKey(""); + break; + case PSK: + bsServ.setHost(contextBootStrap.getBootstrapSecureHost()); + bsServ.setPort(contextBootStrap.getBootstrapSecurePortPsk()); + bsServ.setServerPublicKey(""); + break; + case RPK: + bsServ.setHost(contextBootStrap.getBootstrapSecureHost()); + bsServ.setPort(contextBootStrap.getBootstrapSecurePortRpk()); + bsServ.setServerPublicKey(getRPKPublicKey(this.contextBootStrap.getBootstrapPublicX(), this.contextBootStrap.getBootstrapPublicY())); + break; + case X509: + bsServ.setHost(contextBootStrap.getBootstrapSecureHost()); + bsServ.setPort(contextBootStrap.getBootstrapSecurePortX509()); + bsServ.setServerPublicKey(getServerPublicKeyX509(contextBootStrap.getBootstrapAlias())); + break; + default: + break; + } + } else { + bsServ.setServerId(contextServer.getServerId()); + switch (mode) { + case NO_SEC: + bsServ.setHost(contextServer.getServerHost()); + bsServ.setPort(contextServer.getServerPortNoSecPsk()); + bsServ.setServerPublicKey(""); + break; + case PSK: + bsServ.setHost(contextServer.getServerSecureHost()); + bsServ.setPort(contextServer.getServerPortPsk()); + bsServ.setServerPublicKey(""); + break; + case RPK: + bsServ.setHost(contextServer.getServerSecureHost()); + bsServ.setPort(contextServer.getServerPortRpk()); + bsServ.setServerPublicKey(getRPKPublicKey(this.contextServer.getServerPublicX(), this.contextServer.getServerPublicY())); + break; + case X509: + bsServ.setHost(contextServer.getServerSecureHost()); + bsServ.setPort(contextServer.getServerPortX509()); + bsServ.setServerPublicKey(getServerPublicKeyX509(contextServer.getServerAlias())); + break; + default: + break; + } } + return bsServ; } - return bsServ; - } - /** - * - * @param alias - * @return PublicKey format HexString or null - */ - private String getServerPublicKeyX509 (String alias) { - try { - X509Certificate serverCertificate = (X509Certificate) contextServer.getKeyStoreValue().getCertificate(alias); - return Hex.encodeHexString(serverCertificate.getEncoded()); - } catch (CertificateEncodingException | KeyStoreException e) { - e.printStackTrace(); + /** + * @param alias + * @return PublicKey format HexString or null + */ + private String getServerPublicKeyX509 (String alias){ + try { + X509Certificate serverCertificate = (X509Certificate) contextServer.getKeyStoreValue().getCertificate(alias); + return Hex.encodeHexString(serverCertificate.getEncoded()); + } catch (CertificateEncodingException | KeyStoreException e) { + e.printStackTrace(); + } + return null; } - return null; - } - /** - * - * @param publicServerX - * @param publicServerY - * @return PublicKey format HexString or null - */ - private String getRPKPublicKey(String publicServerX, String publicServerY) { - try { - /** Get Elliptic Curve Parameter spec for secp256r1 */ - AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC"); - algoParameters.init(new ECGenParameterSpec("secp256r1")); - ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class); - if (publicServerX != null && !publicServerX.isEmpty() && publicServerY != null && !publicServerY.isEmpty()) { - /** Get point values */ - byte[] publicX = Hex.decodeHex(publicServerX.toCharArray()); - byte[] publicY = Hex.decodeHex(publicServerY.toCharArray()); - /** Create key specs */ - KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)), - parameterSpec); - /** Get keys */ - PublicKey publicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec); - if (publicKey != null && publicKey.getEncoded().length > 0 ) { - return Hex.encodeHexString(publicKey.getEncoded()); + /** + * @param publicServerX + * @param publicServerY + * @return PublicKey format HexString or null + */ + private String getRPKPublicKey (String publicServerX, String publicServerY){ + try { + /** Get Elliptic Curve Parameter spec for secp256r1 */ + AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC"); + algoParameters.init(new ECGenParameterSpec("secp256r1")); + ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class); + if (publicServerX != null && !publicServerX.isEmpty() && publicServerY != null && !publicServerY.isEmpty()) { + /** Get point values */ + byte[] publicX = Hex.decodeHex(publicServerX.toCharArray()); + byte[] publicY = Hex.decodeHex(publicServerY.toCharArray()); + /** Create key specs */ + KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)), + parameterSpec); + /** Get keys */ + PublicKey publicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec); + if (publicKey != null && publicKey.getEncoded().length > 0) { + return Hex.encodeHexString(publicKey.getEncoded()); + } } + } catch (GeneralSecurityException | IllegalArgumentException e) { + log.error("[{}] Failed generate Server RPK for profile", e.getMessage()); + throw new RuntimeException(e); } - } catch (GeneralSecurityException | IllegalArgumentException e) { - log.error("[{}] Failed generate Server RPK for profile", e.getMessage()); - throw new RuntimeException(e); + return null; } - return null; } -} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mObject.java b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mObject.java index 4bd700fdf9..5afb37c720 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mObject.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mObject.java @@ -16,7 +16,11 @@ package org.thingsboard.server.common.data.lwm2m; import lombok.Data; +import lombok.Getter; +import lombok.Setter; +@Setter +@Getter @Data public class LwM2mObject { int id; diff --git a/ui-ngx/src/app/core/http/device-profile.service.ts b/ui-ngx/src/app/core/http/device-profile.service.ts index 22ff52e99b..816dde3260 100644 --- a/ui-ngx/src/app/core/http/device-profile.service.ts +++ b/ui-ngx/src/app/core/http/device-profile.service.ts @@ -23,6 +23,7 @@ import { PageData } from '@shared/models/page/page-data'; import { DeviceProfile, DeviceProfileInfo, DeviceTransportType } from '@shared/models/device.models'; import { isDefinedAndNotNull } from '@core/utils'; import { ObjectLwM2M, ServerSecurityConfig } from '@home/components/profile/device/lwm2m/profile-config.models'; +import { SortOrder } from '@shared/models/page/sort-order'; @Injectable({ providedIn: 'root' @@ -31,7 +32,8 @@ export class DeviceProfileService { constructor( private http: HttpClient - ) { } + ) { + } public getDeviceProfiles(pageLink: PageLink, config?: RequestConfig): Observable> { return this.http.get>(`/api/deviceProfiles${pageLink.toQuery()}`, defaultHttpOptionsFromConfig(config)); @@ -41,8 +43,14 @@ export class DeviceProfileService { return this.http.get(`/api/deviceProfile/${deviceProfileId}`, defaultHttpOptionsFromConfig(config)); } - public getLwm2mObjects(objectIds: number[], config?: RequestConfig): Observable> { - return this.http.get>(`/api/lwm2m/deviceProfile/${objectIds}`, defaultHttpOptionsFromConfig(config)); + public getLwm2mObjects(objectIds?: number[], searchText?: string, sortOrder?: SortOrder, config?: RequestConfig): + Observable> { + // tslint:disable-next-line:no-debugger + debugger; + return this.http.get> + (`/api/lwm2m/deviceProfile/?objectIds=${objectIds}&searchText=${searchText}&sortProperty=${sortOrder.property} + &sortOrder=${sortOrder.direction}`, + defaultHttpOptionsFromConfig(config)); } public getLwm2mBootstrapSecurityInfo(securityMode: string, bootstrapServerIs: boolean, diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts index 1711f11ade..3dbe82287a 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts @@ -37,6 +37,7 @@ import { deepClone, isUndefined } from '@core/utils'; import { WINDOW } from '@core/services/window.service'; import { JsonObject } from '@angular/compiler-cli/ngcc/src/packages/entry_point'; import { isNotNullOrUndefined } from 'codelyzer/util/isNotNullOrUndefined'; +import { Direction, SortOrder } from '@shared/models/page/sort-order'; @Component({ selector: 'tb-profile-lwm2m-device-transport-configuration', @@ -128,7 +129,11 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro const modelValue = {objectIds: null, objectsList: []}; modelValue.objectIds = this.getObjectsFromJsonAllConfig(); if (modelValue.objectIds !== null) { - this.deviceProfileService.getLwm2mObjects(modelValue.objectIds).subscribe( + const sortOrder = { + property: 'id', + direction: Direction.ASC + }; + this.deviceProfileService.getLwm2mObjects(modelValue.objectIds, null, sortOrder).subscribe( (objectsList) => { modelValue.objectsList = objectsList; this.updateWriteValue(modelValue); From d06ce5555ccfdbbfbbaca236b6ef0b589442e844 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Fri, 22 Jan 2021 16:06:48 +0200 Subject: [PATCH 060/249] Simplified implementation of the overwrite activity time flag --- common/queue/src/main/proto/queue.proto | 1 - .../transport/mqtt/MqttTransportHandler.java | 10 ++++--- .../common/transport/TransportService.java | 5 ++-- .../transport/auth/SessionInfoCreator.java | 23 +++------------- .../service/DefaultTransportService.java | 26 ++++++++++--------- .../transport/service/SessionMetaData.java | 3 ++- .../home/pages/device/device.component.html | 4 +-- .../home/pages/device/device.component.ts | 4 +-- .../assets/locale/locale.constant-en_US.json | 2 +- 9 files changed, 34 insertions(+), 44 deletions(-) diff --git a/common/queue/src/main/proto/queue.proto b/common/queue/src/main/proto/queue.proto index 1d1846dfeb..6864259617 100644 --- a/common/queue/src/main/proto/queue.proto +++ b/common/queue/src/main/proto/queue.proto @@ -53,7 +53,6 @@ message SessionInfoProto { int64 gwSessionIdLSB = 11; int64 deviceProfileIdMSB = 12; int64 deviceProfileIdLSB = 13; - bool activityTimeFromGatewayDevice = 14; } enum SessionEvent { diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java index e7c295b9e6..8a8fcff2a4 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java @@ -55,6 +55,7 @@ import org.thingsboard.server.common.transport.auth.SessionInfoCreator; import org.thingsboard.server.common.transport.auth.TransportDeviceInfo; import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; import org.thingsboard.server.common.transport.service.DefaultTransportService; +import org.thingsboard.server.common.transport.service.SessionMetaData; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceResponseMsg; import org.thingsboard.server.gen.transport.TransportProtos.SessionEvent; @@ -596,7 +597,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement } } - private void checkGatewaySession() { + private void checkGatewaySession(SessionMetaData sessionMetaData) { TransportDeviceInfo device = deviceSessionCtx.getDeviceInfo(); try { JsonNode infoNode = context.getMapper().readTree(device.getAdditionalInfo()); @@ -604,6 +605,9 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement JsonNode gatewayNode = infoNode.get("gateway"); if (gatewayNode != null && gatewayNode.asBoolean()) { gatewaySessionHandler = new GatewaySessionHandler(deviceSessionCtx, sessionId); + if (infoNode.has(DefaultTransportService.OVERWRITE_ACTIVITY_TIME) && infoNode.get(DefaultTransportService.OVERWRITE_ACTIVITY_TIME).isBoolean()) { + sessionMetaData.setOverwriteActivityTime(infoNode.get(DefaultTransportService.OVERWRITE_ACTIVITY_TIME).asBoolean()); + } } } } catch (IOException e) { @@ -639,8 +643,8 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement transportService.process(deviceSessionCtx.getSessionInfo(), DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN), new TransportServiceCallback() { @Override public void onSuccess(Void msg) { - transportService.registerAsyncSession(deviceSessionCtx.getSessionInfo(), MqttTransportHandler.this); - checkGatewaySession(); + SessionMetaData sessionMetaData = transportService.registerAsyncSession(deviceSessionCtx.getSessionInfo(), MqttTransportHandler.this); + checkGatewaySession(sessionMetaData); ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_ACCEPTED, connectMessage)); log.info("[{}] Client connected!", sessionId); } diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportService.java index 6ec1337c62..1d30f561aa 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportService.java @@ -19,6 +19,7 @@ import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.transport.auth.GetOrCreateDeviceFromGatewayResponse; import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; +import org.thingsboard.server.common.transport.service.SessionMetaData; import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg; import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileRequestMsg; @@ -81,9 +82,9 @@ public interface TransportService { void process(SessionInfoProto sessionInfo, ClaimDeviceMsg msg, TransportServiceCallback callback); - void registerAsyncSession(SessionInfoProto sessionInfo, SessionMsgListener listener); + SessionMetaData registerAsyncSession(SessionInfoProto sessionInfo, SessionMsgListener listener); - void registerSyncSession(SessionInfoProto sessionInfo, SessionMsgListener listener, long timeout); + SessionMetaData registerSyncSession(SessionInfoProto sessionInfo, SessionMsgListener listener, long timeout); void reportActivity(SessionInfoProto sessionInfo); diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/auth/SessionInfoCreator.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/auth/SessionInfoCreator.java index ee4d8343a8..ab18b930f9 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/auth/SessionInfoCreator.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/auth/SessionInfoCreator.java @@ -15,20 +15,17 @@ */ package org.thingsboard.server.common.transport.auth; -import com.fasterxml.jackson.databind.JsonNode; import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.common.transport.TransportContext; import org.thingsboard.server.gen.transport.TransportProtos; -import java.io.IOException; import java.util.UUID; @Slf4j public class SessionInfoCreator { public static TransportProtos.SessionInfoProto create(ValidateDeviceCredentialsResponse msg, TransportContext context, UUID sessionId) { - TransportProtos.SessionInfoProto.Builder builder = TransportProtos.SessionInfoProto.newBuilder(); - builder.setNodeId(context.getNodeId()) + return TransportProtos.SessionInfoProto.newBuilder().setNodeId(context.getNodeId()) .setSessionIdMSB(sessionId.getMostSignificantBits()) .setSessionIdLSB(sessionId.getLeastSignificantBits()) .setDeviceIdMSB(msg.getDeviceInfo().getDeviceId().getId().getMostSignificantBits()) @@ -38,22 +35,8 @@ public class SessionInfoCreator { .setDeviceName(msg.getDeviceInfo().getDeviceName()) .setDeviceType(msg.getDeviceInfo().getDeviceType()) .setDeviceProfileIdMSB(msg.getDeviceInfo().getDeviceProfileId().getId().getMostSignificantBits()) - .setDeviceProfileIdLSB(msg.getDeviceInfo().getDeviceProfileId().getId().getLeastSignificantBits()); - if (!"null".equals(msg.getDeviceInfo().getAdditionalInfo())) { - try { - JsonNode infoNode = context.getMapper().readTree(msg.getDeviceInfo().getAdditionalInfo()); - if (infoNode.get("gateway").asBoolean()) { - boolean activityTimeFromGatewayDevice = false; - if (infoNode.has("activityTimeFromGatewayDevice")) { - activityTimeFromGatewayDevice = infoNode.get("activityTimeFromGatewayDevice").asBoolean(); - } - builder.setActivityTimeFromGatewayDevice(activityTimeFromGatewayDevice); - } - } catch (IOException e) { - log.trace("[{}][{}] Failed to fetch device additional info", sessionId, msg.getDeviceInfo().getDeviceName(), e); - } - } - return builder.build(); + .setDeviceProfileIdLSB(msg.getDeviceInfo().getDeviceProfileId().getId().getLeastSignificantBits()) + .build(); } } diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java index 7ff81610b1..8ef0187342 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java @@ -108,6 +108,8 @@ import java.util.concurrent.atomic.AtomicInteger; @TbTransportComponent public class DefaultTransportService implements TransportService { + public static final String OVERWRITE_ACTIVITY_TIME = "overwriteActivityTime"; + @Value("${transport.sessions.inactivity_timeout}") private long sessionInactivityTimeout; @Value("${transport.sessions.report_timeout}") @@ -233,8 +235,10 @@ public class DefaultTransportService implements TransportService { } @Override - public void registerAsyncSession(TransportProtos.SessionInfoProto sessionInfo, SessionMsgListener listener) { - sessions.putIfAbsent(toSessionId(sessionInfo), new SessionMetaData(sessionInfo, TransportProtos.SessionType.ASYNC, listener)); + public SessionMetaData registerAsyncSession(TransportProtos.SessionInfoProto sessionInfo, SessionMsgListener listener) { + SessionMetaData newValue = new SessionMetaData(sessionInfo, TransportProtos.SessionType.ASYNC, listener); + SessionMetaData oldValue = sessions.putIfAbsent(toSessionId(sessionInfo), newValue); + return oldValue != null ? oldValue : newValue; } @Override @@ -513,7 +517,7 @@ public class DefaultTransportService implements TransportService { if (sessionInfo.getGwSessionIdMSB() != 0 && sessionInfo.getGwSessionIdLSB() != 0) { SessionMetaData gwMetaData = sessions.get(new UUID(sessionInfo.getGwSessionIdMSB(), sessionInfo.getGwSessionIdLSB())); - if (gwMetaData != null && gwMetaData.getSessionInfo().getActivityTimeFromGatewayDevice()) { + if (gwMetaData != null && gwMetaData.isOverwriteActivityTime()) { lastActivityTime = Math.max(gwMetaData.getLastActivityTime(), lastActivityTime); } } @@ -547,7 +551,7 @@ public class DefaultTransportService implements TransportService { } @Override - public void registerSyncSession(TransportProtos.SessionInfoProto sessionInfo, SessionMsgListener listener, long timeout) { + public SessionMetaData registerSyncSession(TransportProtos.SessionInfoProto sessionInfo, SessionMsgListener listener, long timeout) { SessionMetaData currentSession = new SessionMetaData(sessionInfo, TransportProtos.SessionType.SYNC, listener); sessions.putIfAbsent(toSessionId(sessionInfo), currentSession); @@ -557,6 +561,7 @@ public class DefaultTransportService implements TransportService { }, timeout, TimeUnit.MILLISECONDS); currentSession.setScheduledFuture(executorFuture); + return currentSession; } @Override @@ -703,21 +708,18 @@ public class DefaultTransportService implements TransportService { } else { newDeviceProfile = null; } - TransportProtos.SessionInfoProto.Builder newSessionInfoBuilder = TransportProtos.SessionInfoProto.newBuilder() + TransportProtos.SessionInfoProto newSessionInfo = TransportProtos.SessionInfoProto.newBuilder() .mergeFrom(md.getSessionInfo()) .setDeviceProfileIdMSB(deviceProfileIdMSB) .setDeviceProfileIdLSB(deviceProfileIdLSB) .setDeviceName(device.getName()) - .setDeviceType(device.getType()); + .setDeviceType(device.getType()).build(); if (device.getAdditionalInfo().has("gateway") && device.getAdditionalInfo().get("gateway").asBoolean() - && device.getAdditionalInfo().has("activityTimeFromGatewayDevice")) { - boolean activityTimeFromGatewayDevice = device.getAdditionalInfo().get("activityTimeFromGatewayDevice").asBoolean(); - if (md.getSessionInfo().getActivityTimeFromGatewayDevice() != activityTimeFromGatewayDevice) { - newSessionInfoBuilder.setActivityTimeFromGatewayDevice(activityTimeFromGatewayDevice); - } + && device.getAdditionalInfo().has(OVERWRITE_ACTIVITY_TIME) + && device.getAdditionalInfo().get(OVERWRITE_ACTIVITY_TIME).isBoolean()) { + md.setOverwriteActivityTime(device.getAdditionalInfo().get(OVERWRITE_ACTIVITY_TIME).asBoolean()); } - TransportProtos.SessionInfoProto newSessionInfo = newSessionInfoBuilder.build(); md.setSessionInfo(newSessionInfo); transportCallbackExecutor.submit(() -> md.getListener().onDeviceUpdate(newSessionInfo, device, Optional.ofNullable(newDeviceProfile))); } diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/SessionMetaData.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/SessionMetaData.java index c81ca05bc1..bb0ed7aa58 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/SessionMetaData.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/SessionMetaData.java @@ -25,7 +25,7 @@ import java.util.concurrent.ScheduledFuture; * Created by ashvayka on 15.10.18. */ @Data -class SessionMetaData { +public class SessionMetaData { private volatile TransportProtos.SessionInfoProto sessionInfo; private final TransportProtos.SessionType sessionType; @@ -36,6 +36,7 @@ class SessionMetaData { private volatile long lastReportedActivityTime; private volatile boolean subscribedToAttributes; private volatile boolean subscribedToRPC; + private volatile boolean overwriteActivityTime; SessionMetaData(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.SessionType sessionType, SessionMsgListener listener) { this.sessionInfo = sessionInfo; diff --git a/ui-ngx/src/app/modules/home/pages/device/device.component.html b/ui-ngx/src/app/modules/home/pages/device/device.component.html index 1ea3b380b9..b01aced285 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device.component.html +++ b/ui-ngx/src/app/modules/home/pages/device/device.component.html @@ -105,8 +105,8 @@ {{ 'device.is-gateway' | translate }} - {{ 'device.activity-time-from-gateway-device' | translate }} + formControlName="overwriteActivityTime"> + {{ 'device.overwrite-activity-time' | translate }}
diff --git a/ui-ngx/src/app/modules/home/pages/device/device.component.ts b/ui-ngx/src/app/modules/home/pages/device/device.component.ts index 9d865a09af..660b6341ca 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device.component.ts +++ b/ui-ngx/src/app/modules/home/pages/device/device.component.ts @@ -84,7 +84,7 @@ export class DeviceComponent extends EntityComponent { additionalInfo: this.fb.group( { gateway: [entity && entity.additionalInfo ? entity.additionalInfo.gateway : false], - activityTimeFromGatewayDevice: [entity && entity.additionalInfo ? entity.additionalInfo.activityTimeFromGatewayDevice: false], + overwriteActivityTime: [entity && entity.additionalInfo ? entity.additionalInfo.overwriteActivityTime: false], description: [entity && entity.additionalInfo ? entity.additionalInfo.description : ''], } ) @@ -101,7 +101,7 @@ export class DeviceComponent extends EntityComponent { additionalInfo: { gateway: entity.additionalInfo ? entity.additionalInfo.gateway : false, - activityTimeFromGatewayDevice: entity.additionalInfo ? entity.additionalInfo.activityTimeFromGatewayDevice : false + overwriteActivityTime: entity.additionalInfo ? entity.additionalInfo.overwriteActivityTime : false } }); this.entityForm.patchValue({additionalInfo: {description: entity.additionalInfo ? entity.additionalInfo.description : ''}}); diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index a574435358..ea0e45cbd2 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -906,7 +906,7 @@ "unable-delete-device-alias-title": "Unable to delete device alias", "unable-delete-device-alias-text": "Device alias '{{deviceAlias}}' can't be deleted as it used by the following widget(s):
{{widgetsList}}", "is-gateway": "Is gateway", - "activity-time-from-gateway-device": "Activity time from gateway device", + "overwrite-activity-time": "Overwrite activity time for connected device", "public": "Public", "device-public": "Device is public", "select-device": "Select device", From de77c53fcc07b693d949d4beceb32ab192c1015f Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Fri, 22 Jan 2021 16:14:39 +0200 Subject: [PATCH 061/249] UI: Refactoring LwM2M --- .../app/core/http/device-profile.service.ts | 16 +- ...ile-transport-configuration.component.html | 62 +++--- ...ofile-transport-configuration.component.ts | 195 +++++++++--------- 3 files changed, 141 insertions(+), 132 deletions(-) diff --git a/ui-ngx/src/app/core/http/device-profile.service.ts b/ui-ngx/src/app/core/http/device-profile.service.ts index 816dde3260..df68af629e 100644 --- a/ui-ngx/src/app/core/http/device-profile.service.ts +++ b/ui-ngx/src/app/core/http/device-profile.service.ts @@ -43,14 +43,16 @@ export class DeviceProfileService { return this.http.get(`/api/deviceProfile/${deviceProfileId}`, defaultHttpOptionsFromConfig(config)); } - public getLwm2mObjects(objectIds?: number[], searchText?: string, sortOrder?: SortOrder, config?: RequestConfig): + public getLwm2mObjects(objectIds: number[] = [], searchText?: string, sortOrder?: SortOrder, config?: RequestConfig): Observable> { - // tslint:disable-next-line:no-debugger - debugger; - return this.http.get> - (`/api/lwm2m/deviceProfile/?objectIds=${objectIds}&searchText=${searchText}&sortProperty=${sortOrder.property} - &sortOrder=${sortOrder.direction}`, - defaultHttpOptionsFromConfig(config)); + let url = `/api/lwm2m/deviceProfile/?objectIds=${objectIds}`; + if (isDefinedAndNotNull(searchText)) { + url += `&searchText=${searchText}`; + } + if (isDefinedAndNotNull(sortOrder)) { + url += `&sortProperty=${sortOrder.property}&sortOrder=${sortOrder.direction}`; + } + return this.http.get>(url, defaultHttpOptionsFromConfig(config)); } public getLwm2mBootstrapSecurityInfo(securityMode: string, bootstrapServerIs: boolean, diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html index 7b49f8ffd6..57b767fb07 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html @@ -15,11 +15,11 @@ limitations under the License. --> - -
- - - +
+ + + +
- - - - +
+
+
+ + +
@@ -52,7 +54,7 @@ {{ 'device-profile.lwm2m.short-id' | translate }} - + {{ 'device-profile.lwm2m.short-id' | translate }} {{ 'device-profile.lwm2m.required' | translate }} @@ -61,7 +63,7 @@ {{ 'device-profile.lwm2m.lifetime' | translate }} + *ngIf="lwm2mDeviceProfileFormGroup.get('lifetime').hasError('required')"> {{ 'device-profile.lwm2m.lifetime' | translate }} {{ 'device-profile.lwm2m.required' | translate }} @@ -72,7 +74,7 @@ {{ 'device-profile.lwm2m.default-min-period' | translate }} + *ngIf="lwm2mDeviceProfileFormGroup.get('defaultMinPeriod').hasError('required')"> {{ 'device-profile.lwm2m.default-min-period' | translate }} {{ 'device-profile.lwm2m.required' | translate }} @@ -80,7 +82,7 @@ {{ 'device-profile.lwm2m.binding' | translate }} - + {{ 'device-profile.lwm2m.binding' | translate }} {{ 'device-profile.lwm2m.required' | translate }} @@ -133,20 +135,20 @@
- - - - -
- - -
-
-
- -
- +
+ + + + +
+ + +
+
+
+ + diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts index 3dbe82287a..d5dc7e90b6 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts @@ -33,11 +33,10 @@ import { TELEMETRY } from './profile-config.models'; import { DeviceProfileService } from '@core/http/device-profile.service'; -import { deepClone, isUndefined } from '@core/utils'; +import { deepClone, isDefinedAndNotNull, isUndefined } from '@core/utils'; import { WINDOW } from '@core/services/window.service'; import { JsonObject } from '@angular/compiler-cli/ngcc/src/packages/entry_point'; -import { isNotNullOrUndefined } from 'codelyzer/util/isNotNullOrUndefined'; -import { Direction, SortOrder } from '@shared/models/page/sort-order'; +import { Direction } from '@shared/models/page/sort-order'; @Component({ selector: 'tb-profile-lwm2m-device-transport-configuration', @@ -54,7 +53,8 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro private requiredValue: boolean; private disabled = false; - lwm2mDeviceProfileTransportConfFormGroup: FormGroup; + lwm2mDeviceProfileFormGroup: FormGroup; + lwm2mDeviceConfigFormGroup: FormGroup; observeAttr = OBSERVE_ATTR; observe = OBSERVE; attribute = ATTR; @@ -80,7 +80,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro private fb: FormBuilder, private deviceProfileService: DeviceProfileService, @Inject(WINDOW) private window: Window) { - this.lwm2mDeviceProfileTransportConfFormGroup = this.fb.group({ + this.lwm2mDeviceProfileFormGroup = this.fb.group({ objectIds: [{}, Validators.required], observeAttrTelemetry: [{clientLwM2M: []}, Validators.required], shortId: [null, Validators.required], @@ -90,9 +90,18 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro binding: ['U', Validators.required], bootstrapServer: [null, Validators.required], lwm2mServer: [null, Validators.required], - configurationJson: [null, Validators.required], }); - this.lwm2mDeviceProfileTransportConfFormGroup.valueChanges.subscribe(() => { + this.lwm2mDeviceConfigFormGroup = this.fb.group({ + configurationJson: [null, Validators.required] + }); + this.lwm2mDeviceProfileFormGroup.valueChanges.subscribe(() => { + console.warn('main form'); + if (!this.disabled) { + this.updateModel(); + } + }); + this.lwm2mDeviceConfigFormGroup.valueChanges.subscribe(() => { + console.warn('config form'); if (!this.disabled) { this.updateModel(); } @@ -110,18 +119,19 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro setDisabledState(isDisabled: boolean): void { this.disabled = isDisabled; if (isDisabled) { - this.lwm2mDeviceProfileTransportConfFormGroup.disable({emitEvent: false}); + this.lwm2mDeviceProfileFormGroup.disable({emitEvent: false}); + this.lwm2mDeviceConfigFormGroup.disable({emitEvent: false}); } else { - this.lwm2mDeviceProfileTransportConfFormGroup.enable({emitEvent: false}); + this.lwm2mDeviceProfileFormGroup.enable({emitEvent: false}); + this.lwm2mDeviceConfigFormGroup.enable({emitEvent: false}); } } writeValue(value: any | null): void { this.configurationValue = (Object.keys(value).length === 0) ? getDefaultProfileConfig() : value; - this.lwm2mDeviceProfileTransportConfFormGroup.patchValue({ + this.lwm2mDeviceConfigFormGroup.patchValue({ configurationJson: this.configurationValue - }, - {emitEvent: false}); + }, {emitEvent: false}); this.initWriteValue(); } @@ -146,7 +156,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro private updateWriteValue = (value: any): void => { const objectsList = value.objectsList; - this.lwm2mDeviceProfileTransportConfFormGroup.patchValue({ + this.lwm2mDeviceProfileFormGroup.patchValue({ objectIds: value, observeAttrTelemetry: {clientLwM2M: this.getObserveAttrTelemetryObjects(objectsList)}, shortId: this.configurationValue.bootstrap.servers.shortId, @@ -162,20 +172,20 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro private updateModel = (): void => { let configuration: DeviceProfileTransportConfiguration = null; - if (this.lwm2mDeviceProfileTransportConfFormGroup.valid) { + if (this.lwm2mDeviceConfigFormGroup.valid) { this.upDateValueToJson(); - configuration = this.lwm2mDeviceProfileTransportConfFormGroup.getRawValue().configurationJson; + configuration = this.lwm2mDeviceConfigFormGroup.getRawValue().configurationJson; configuration.type = DeviceTransportType.LWM2M; } this.propagateChange(configuration); } private updateObserveAttrTelemetryObjectFormGroup = (objectsList: ObjectLwM2M[]): void => { - this.lwm2mDeviceProfileTransportConfFormGroup.patchValue({ + this.lwm2mDeviceProfileFormGroup.patchValue({ observeAttrTelemetry: {clientLwM2M: this.getObserveAttrTelemetryObjects(objectsList)} }, {emitEvent: false}); - this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').markAsPristine({ + this.lwm2mDeviceProfileFormGroup.get('observeAttrTelemetry').markAsPristine({ onlySelf: true }); } @@ -186,11 +196,11 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } private upDateValueToJsonTab0 = (): void => { - if (!this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').pristine) { + if (!this.lwm2mDeviceProfileFormGroup.get('observeAttrTelemetry').pristine) { this.upDateObserveAttrTelemetryFromGroupToJson( - this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').value.clientLwM2M + this.lwm2mDeviceProfileFormGroup.get('observeAttrTelemetry').value.clientLwM2M ); - this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').markAsPristine({ + this.lwm2mDeviceProfileFormGroup.get('observeAttrTelemetry').markAsPristine({ onlySelf: true }); this.upDateJsonAllConfig(); @@ -199,16 +209,16 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro private upDateValueToJsonTab1 = (): void => { this.upDateValueServersToJson(); - if (!this.lwm2mDeviceProfileTransportConfFormGroup.get('bootstrapServer').pristine) { - this.configurationValue.bootstrap.bootstrapServer = this.lwm2mDeviceProfileTransportConfFormGroup.get('bootstrapServer').value; - this.lwm2mDeviceProfileTransportConfFormGroup.get('bootstrapServer').markAsPristine({ + if (!this.lwm2mDeviceProfileFormGroup.get('bootstrapServer').pristine) { + this.configurationValue.bootstrap.bootstrapServer = this.lwm2mDeviceProfileFormGroup.get('bootstrapServer').value; + this.lwm2mDeviceProfileFormGroup.get('bootstrapServer').markAsPristine({ onlySelf: true }); this.upDateJsonAllConfig(); } - if (!this.lwm2mDeviceProfileTransportConfFormGroup.get('lwm2mServer').pristine) { - this.configurationValue.bootstrap.lwm2mServer = this.lwm2mDeviceProfileTransportConfFormGroup.get('lwm2mServer').value; - this.lwm2mDeviceProfileTransportConfFormGroup.get('lwm2mServer').markAsPristine({ + if (!this.lwm2mDeviceProfileFormGroup.get('lwm2mServer').pristine) { + this.configurationValue.bootstrap.lwm2mServer = this.lwm2mDeviceProfileFormGroup.get('lwm2mServer').value; + this.lwm2mDeviceProfileFormGroup.get('lwm2mServer').markAsPristine({ onlySelf: true }); this.upDateJsonAllConfig(); @@ -217,37 +227,37 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro private upDateValueServersToJson = (): void => { const bootstrapServers = this.configurationValue.bootstrap.servers; - if (!this.lwm2mDeviceProfileTransportConfFormGroup.get('shortId').pristine) { - bootstrapServers.shortId = this.lwm2mDeviceProfileTransportConfFormGroup.get('shortId').value; - this.lwm2mDeviceProfileTransportConfFormGroup.get('shortId').markAsPristine({ + if (!this.lwm2mDeviceProfileFormGroup.get('shortId').pristine) { + bootstrapServers.shortId = this.lwm2mDeviceProfileFormGroup.get('shortId').value; + this.lwm2mDeviceProfileFormGroup.get('shortId').markAsPristine({ onlySelf: true }); this.upDateJsonAllConfig(); } - if (!this.lwm2mDeviceProfileTransportConfFormGroup.get('lifetime').pristine) { - bootstrapServers.lifetime = this.lwm2mDeviceProfileTransportConfFormGroup.get('lifetime').value; - this.lwm2mDeviceProfileTransportConfFormGroup.get('lifetime').markAsPristine({ + if (!this.lwm2mDeviceProfileFormGroup.get('lifetime').pristine) { + bootstrapServers.lifetime = this.lwm2mDeviceProfileFormGroup.get('lifetime').value; + this.lwm2mDeviceProfileFormGroup.get('lifetime').markAsPristine({ onlySelf: true }); this.upDateJsonAllConfig(); } - if (!this.lwm2mDeviceProfileTransportConfFormGroup.get('defaultMinPeriod').pristine) { - bootstrapServers.defaultMinPeriod = this.lwm2mDeviceProfileTransportConfFormGroup.get('defaultMinPeriod').value; - this.lwm2mDeviceProfileTransportConfFormGroup.get('defaultMinPeriod').markAsPristine({ + if (!this.lwm2mDeviceProfileFormGroup.get('defaultMinPeriod').pristine) { + bootstrapServers.defaultMinPeriod = this.lwm2mDeviceProfileFormGroup.get('defaultMinPeriod').value; + this.lwm2mDeviceProfileFormGroup.get('defaultMinPeriod').markAsPristine({ onlySelf: true }); this.upDateJsonAllConfig(); } - if (!this.lwm2mDeviceProfileTransportConfFormGroup.get('notifIfDisabled').pristine) { - bootstrapServers.notifIfDisabled = this.lwm2mDeviceProfileTransportConfFormGroup.get('notifIfDisabled').value; - this.lwm2mDeviceProfileTransportConfFormGroup.get('notifIfDisabled').markAsPristine({ + if (!this.lwm2mDeviceProfileFormGroup.get('notifIfDisabled').pristine) { + bootstrapServers.notifIfDisabled = this.lwm2mDeviceProfileFormGroup.get('notifIfDisabled').value; + this.lwm2mDeviceProfileFormGroup.get('notifIfDisabled').markAsPristine({ onlySelf: true }); this.upDateJsonAllConfig(); } - if (!this.lwm2mDeviceProfileTransportConfFormGroup.get('binding').pristine) { - bootstrapServers.binding = this.lwm2mDeviceProfileTransportConfFormGroup.get('binding').value; - this.lwm2mDeviceProfileTransportConfFormGroup.get('binding').markAsPristine({ + if (!this.lwm2mDeviceProfileFormGroup.get('binding').pristine) { + bootstrapServers.binding = this.lwm2mDeviceProfileFormGroup.get('binding').value; + this.lwm2mDeviceProfileFormGroup.get('binding').markAsPristine({ onlySelf: true }); this.upDateJsonAllConfig(); @@ -255,55 +265,50 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } private getObserveAttrTelemetryObjects = (listObject: ObjectLwM2M[]): ObjectLwM2M [] => { - const clientObserveAttr = listObject; + const clientObserveAttrTelemetry = listObject; if (this.configurationValue[this.observeAttr]) { const observeArray = this.configurationValue[this.observeAttr][this.observe]; const attributeArray = this.configurationValue[this.observeAttr][this.attribute]; const telemetryArray = this.configurationValue[this.observeAttr][this.telemetry]; const keyNameJson = this.configurationValue[this.observeAttr][this.keyName]; - if (this.includesInstancesNo(attributeArray, telemetryArray)) { - this.addInstances(attributeArray, telemetryArray, clientObserveAttr); + if (this.includesNotZeroInstance(attributeArray, telemetryArray)) { + this.addInstances(attributeArray, telemetryArray, clientObserveAttrTelemetry); } - if (observeArray) { - this.updateObserveAttrTelemetryObjects(observeArray, clientObserveAttr, 'observe'); + if (isDefinedAndNotNull(observeArray)) { + this.updateObserveAttrTelemetryObjects(observeArray, clientObserveAttrTelemetry, 'observe'); } - if (attributeArray) { - this.updateObserveAttrTelemetryObjects(attributeArray, clientObserveAttr, 'attribute'); + if (isDefinedAndNotNull(attributeArray)) { + this.updateObserveAttrTelemetryObjects(attributeArray, clientObserveAttrTelemetry, 'attribute'); } - if (telemetryArray) { - this.updateObserveAttrTelemetryObjects(telemetryArray, clientObserveAttr, 'telemetry'); + if (isDefinedAndNotNull(telemetryArray)) { + this.updateObserveAttrTelemetryObjects(telemetryArray, clientObserveAttrTelemetry, 'telemetry'); } - if (keyNameJson) { - this.updateKeyNameObjects(deepClone(keyNameJson), clientObserveAttr); + if (isDefinedAndNotNull(keyNameJson)) { + this.updateKeyNameObjects(keyNameJson, clientObserveAttrTelemetry); } } - clientObserveAttr.forEach(obj => { + clientObserveAttrTelemetry.forEach(obj => { obj.instances.sort((a, b) => a.id - b.id); }); - return clientObserveAttr; + return clientObserveAttrTelemetry; } - private includesInstancesNo = (attributeArray: Array, telemetryArray: Array): boolean => { - const isIdIndex = (element) => !element.includes('/0/'); - return attributeArray.findIndex(isIdIndex) >= 0 || telemetryArray.findIndex(isIdIndex) >= 0; + private includesNotZeroInstance = (attribute: string[], telemetry: string[]): boolean => { + const isNotZeroInstanceId = (instance) => !instance.includes('/0/'); + return attribute.some(isNotZeroInstanceId) || telemetry.some(isNotZeroInstanceId); } - private addInstances = (attributeArray: Array, telemetryArray: Array, - clientObserveAttr: ObjectLwM2M[]): void => { - const attr = [] as Array; - [...attributeArray].filter(x => (!x.includes('/0/'))).forEach(x => { - attr.push(this.convertPathToInstance(x)); - }); - const telemetry = [] as Array; - [...telemetryArray].filter(x => (!x.includes('/0/'))).forEach(x => { - telemetry.push(this.convertPathToInstance(x)); - }); - const instancesNoZero = new Set(attr.concat(telemetry).sort()); - instancesNoZero.forEach(path => { + private addInstances = (attribute: string[], telemetry: string[], clientObserveAttrTelemetry: ObjectLwM2M[]): void => { + const instancesPath = attribute.concat(telemetry) + .filter(instance => !instance.includes('/0/')) + .map(instance => this.convertPathToInstance(instance)) + .sort(); + + new Set(instancesPath).forEach(path => { const pathParameter = Array.from(path.split('/'), Number); - const objectLwM2M = clientObserveAttr.find(x => (x.id === pathParameter[0])); + const objectLwM2M = clientObserveAttrTelemetry.find(x => x.id === pathParameter[0]); if (objectLwM2M) { - const instance = deepClone(objectLwM2M.instances[0]) as Instance; + const instance = deepClone(objectLwM2M.instances[0]); instance.id = pathParameter[1]; objectLwM2M.instances.push(instance); } @@ -311,36 +316,36 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } private convertPathToInstance = (path: string): string => { - const newX = Array.from(path.substring(1).split('/'), Number); - return [newX[0], newX[1]].join('/'); + const [objectId, instanceId] = path.substring(1).split('/'); + return `${objectId}/${instanceId}`; } - private updateObserveAttrTelemetryObjects = (isParameter: Array, clientObserveAttr: ObjectLwM2M[], + private updateObserveAttrTelemetryObjects = (parameters: string[], clientObserveAttrTelemetry: ObjectLwM2M[], nameParameter: string): void => { - isParameter.forEach(attr => { - const idKeys = Array.from(attr.substring(1).split('/'), Number); - clientObserveAttr - .forEach(e => { - if (e.id === idKeys[0]) { - const instance = e.instances.find(itrInstance => itrInstance.id === idKeys[1]); - if (isNotNullOrUndefined(instance)) { - instance.resources.find(resource => resource.id === idKeys[2])[nameParameter] = true; + parameters.forEach(parameter => { + const [objectId, instanceId, resourceId] = Array.from(parameter.substring(1).split('/'), Number); + clientObserveAttrTelemetry + .forEach(key => { + if (key.id === objectId) { + const instance = key.instances.find(itrInstance => itrInstance.id === instanceId); + if (isDefinedAndNotNull(instance)) { + instance.resources.find(resource => resource.id === resourceId)[nameParameter] = true; } } }); }); } - private updateKeyNameObjects = (nameJson: JsonObject, clientObserveAttr: ObjectLwM2M[]): void => { + private updateKeyNameObjects = (nameJson: JsonObject, clientObserveAttrTelemetry: ObjectLwM2M[]): void => { const keyName = JSON.parse(JSON.stringify(nameJson)); Object.keys(keyName).forEach(key => { - const idKeys = Array.from(key.substring(1).split('/'), Number); - clientObserveAttr - .forEach(e => { - if (e.id === idKeys[0]) { - e.instances - .find(instance => instance.id === idKeys[1]).resources - .find(resource => resource.id === idKeys[2]).keyName = keyName[key]; + const [objectId, instanceId, resourceId] = Array.from(key.substring(1).split('/'), Number); + clientObserveAttrTelemetry + .forEach(object => { + if (object.id === objectId) { + object.instances + .find(instance => instance.id === instanceId).resources + .find(resource => resource.id === resourceId).keyName = keyName[key]; } }); }); @@ -444,7 +449,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro paths.forEach(path => { const pathParameter = this.findIndexesForIds(path); if (pathParameter.length === 3) { - keyNameNew[path] = this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').value + keyNameNew[path] = this.lwm2mDeviceProfileFormGroup.get('observeAttrTelemetry').value .clientLwM2M[pathParameter[0]].instances[pathParameter[1]].resources[pathParameter[2]][this.keyName]; } }); @@ -455,7 +460,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro const pathParameter = Array.from(path.substring(1).split('/'), Number); const pathParameterIndexes: number[] = []; const objectsOld = deepClone( - this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').value.clientLwM2M) as ObjectLwM2M[]; + this.lwm2mDeviceProfileFormGroup.get('observeAttrTelemetry').value.clientLwM2M) as ObjectLwM2M[]; let isIdIndex = (element) => element.id === pathParameter[0]; const objIndex = objectsOld.findIndex(isIdIndex); if (objIndex >= 0) { @@ -497,10 +502,10 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } private upDateJsonAllConfig = (): void => { - this.lwm2mDeviceProfileTransportConfFormGroup.patchValue({ + this.lwm2mDeviceProfileFormGroup.patchValue({ configurationJson: this.configurationValue }, {emitEvent: false}); - this.lwm2mDeviceProfileTransportConfFormGroup.markAsPristine({ + this.lwm2mDeviceProfileFormGroup.markAsPristine({ onlySelf: true }); } @@ -510,7 +515,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } removeObjectsList = (value: ObjectLwM2M): void => { - const objectsOld = deepClone(this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').value.clientLwM2M); + const objectsOld = deepClone(this.lwm2mDeviceProfileFormGroup.get('observeAttrTelemetry').value.clientLwM2M); const isIdIndex = (element) => element.id === value.id; const index = objectsOld.findIndex(isIdIndex); if (index >= 0) { From 90334db15746d5dd5dfd4ca768d27ce410d7b6fe Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Fri, 22 Jan 2021 17:06:53 +0200 Subject: [PATCH 062/249] Refactoring of HTTP and MQTT client credentials --- .../credentials/CertPemCredentials.java | 3 +- .../rule/engine/mqtt/TbMqttNode.java | 39 +++++++-------- .../mqtt/azure/AzureIotHubSasCredentials.java | 26 +--------- .../engine/mqtt/azure/TbAzureIotHubNode.java | 50 +++++++------------ .../rule/engine/rest/TbHttpClient.java | 21 ++++---- .../credentials/BasicCredentialsTest.java | 34 ------------- 6 files changed, 51 insertions(+), 122 deletions(-) delete mode 100644 rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/credentials/BasicCredentialsTest.java diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CertPemCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CertPemCredentials.java index a1c40f0d24..0a97be3bd0 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CertPemCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CertPemCredentials.java @@ -66,6 +66,7 @@ public class CertPemCredentials implements ClientCredentials { return CredentialsType.CERT_PEM; } + @Override public SslContext initSslContext() { try { Security.addProvider(new BouncyCastleProvider()); @@ -120,7 +121,7 @@ public class CertPemCredentials implements ClientCredentials { return keyManagerFactory; } - private TrustManagerFactory createAndInitTrustManagerFactory() throws Exception { + protected TrustManagerFactory createAndInitTrustManagerFactory() throws Exception { X509Certificate caCertHolder; caCertHolder = readCertFile(caCert); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java index ba1d0caea2..2ecf770e19 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java @@ -20,6 +20,7 @@ import io.netty.handler.codec.mqtt.MqttQoS; import io.netty.handler.ssl.SslContext; import io.netty.util.concurrent.Future; import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; import org.springframework.util.StringUtils; import org.thingsboard.mqtt.MqttClient; import org.thingsboard.mqtt.MqttClientConfig; @@ -78,14 +79,14 @@ public class TbMqttNode implements TbNode { String topic = TbNodeUtils.processPattern(this.mqttNodeConfiguration.getTopicPattern(), msg.getMetaData()); this.mqttClient.publish(topic, Unpooled.wrappedBuffer(msg.getData().getBytes(UTF8)), MqttQoS.AT_LEAST_ONCE) .addListener(future -> { - if (future.isSuccess()) { - ctx.tellSuccess(msg); - } else { - TbMsg next = processException(ctx, msg, future.cause()); - ctx.tellFailure(next, future.cause()); - } - } - ); + if (future.isSuccess()) { + ctx.tellSuccess(msg); + } else { + TbMsg next = processException(ctx, msg, future.cause()); + ctx.tellFailure(next, future.cause()); + } + } + ); } private TbMsg processException(TbContext ctx, TbMsg origMsg, Throwable e) { @@ -108,12 +109,7 @@ public class TbMqttNode implements TbNode { } config.setCleanSession(this.mqttNodeConfiguration.isCleanSession()); - ClientCredentials credentials = this.mqttNodeConfiguration.getCredentials(); - if (credentials.getType() == CredentialsType.BASIC) { - config.setUsername(((BasicCredentials) credentials).getUsername()); - config.setPassword(((BasicCredentials) credentials).getPassword()); - } - + prepareMqttClientConfig(config); MqttClient client = MqttClient.create(config, null); client.setEventLoop(ctx.getSharedEventLoop()); Future connectFuture = client.connect(this.mqttNodeConfiguration.getHost(), this.mqttNodeConfiguration.getPort()); @@ -135,14 +131,17 @@ public class TbMqttNode implements TbNode { return client; } - private SslContext getSslContext() throws SSLException { + protected void prepareMqttClientConfig(MqttClientConfig config) throws SSLException { ClientCredentials credentials = this.mqttNodeConfiguration.getCredentials(); - SslContext sslContext = credentials.initSslContext(); - if (!this.mqttNodeConfiguration.isSsl() && - (credentials.getType() == CredentialsType.ANONYMOUS || credentials.getType() == CredentialsType.BASIC)) { - sslContext = null; + if (credentials.getType() == CredentialsType.BASIC) { + BasicCredentials basicCredentials = (BasicCredentials) credentials; + config.setUsername(basicCredentials.getUsername()); + config.setPassword(basicCredentials.getPassword()); } - return sslContext; + } + + private SslContext getSslContext() throws SSLException { + return this.mqttNodeConfiguration.isSsl() ? this.mqttNodeConfiguration.getCredentials().initSslContext() : null; } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/AzureIotHubSasCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/AzureIotHubSasCredentials.java index f938e6e603..5155acf831 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/AzureIotHubSasCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/AzureIotHubSasCredentials.java @@ -29,6 +29,7 @@ import org.thingsboard.rule.engine.credentials.CredentialsType; import javax.net.ssl.TrustManagerFactory; import java.io.ByteArrayInputStream; +import java.io.InputStream; import java.security.KeyStore; import java.security.Security; import java.security.cert.CertificateFactory; @@ -63,29 +64,4 @@ public class AzureIotHubSasCredentials extends CertPemCredentials { return CredentialsType.SAS; } - private TrustManagerFactory createAndInitTrustManagerFactory() throws Exception { - X509Certificate caCertHolder; - caCertHolder = readCertFile(caCert); - - KeyStore caKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - caKeyStore.load(null, null); - caKeyStore.setCertificateEntry("caCert-cert", caCertHolder); - - TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - trustManagerFactory.init(caKeyStore); - return trustManagerFactory; - } - - private X509Certificate readCertFile(String fileContent) throws Exception { - X509Certificate certificate = null; - if (fileContent != null && !fileContent.trim().isEmpty()) { - fileContent = fileContent.replace("-----BEGIN CERTIFICATE-----", "") - .replace("-----END CERTIFICATE-----", "") - .replaceAll("\\s", ""); - byte[] decoded = Base64.decodeBase64(fileContent); - CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); - certificate = (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(decoded)); - } - return certificate; - } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNode.java index 4ada1e0d39..9718b10f9c 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNode.java @@ -15,14 +15,18 @@ */ package org.thingsboard.rule.engine.mqtt.azure; +import io.netty.handler.codec.mqtt.MqttVersion; import io.netty.handler.ssl.SslContext; import lombok.extern.slf4j.Slf4j; +import org.springframework.util.StringUtils; import org.thingsboard.common.util.AzureIotHubUtil; +import org.thingsboard.mqtt.MqttClientConfig; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.rule.engine.credentials.BasicCredentials; import org.thingsboard.rule.engine.credentials.CertPemCredentials; import org.thingsboard.rule.engine.credentials.ClientCredentials; import org.thingsboard.rule.engine.credentials.CredentialsType; @@ -50,42 +54,24 @@ public class TbAzureIotHubNode extends TbMqttNode { mqttNodeConfiguration.setPort(8883); mqttNodeConfiguration.setCleanSession(true); ClientCredentials credentials = mqttNodeConfiguration.getCredentials(); - mqttNodeConfiguration.setCredentials(new ClientCredentials() { - @Override - public CredentialsType getType() { - return credentials.getType(); + if (CredentialsType.CERT_PEM == credentials.getType()) { + CertPemCredentials pemCredentials = (CertPemCredentials) credentials; + if (pemCredentials.getCaCert() == null || pemCredentials.getCaCert().isEmpty()) { + pemCredentials.setCaCert(AzureIotHubUtil.getDefaultCaCert()); } - - @Override - public SslContext initSslContext() throws SSLException { - if (credentials instanceof AzureIotHubSasCredentials) { - AzureIotHubSasCredentials sasCredentials = (AzureIotHubSasCredentials) credentials; - if (sasCredentials.getCaCert() == null || sasCredentials.getCaCert().isEmpty()) { - sasCredentials.setCaCert(AzureIotHubUtil.getDefaultCaCert()); - } - } else if (credentials instanceof CertPemCredentials) { - CertPemCredentials pemCredentials = (CertPemCredentials) credentials; - if (pemCredentials.getCaCert() == null || pemCredentials.getCaCert().isEmpty()) { - pemCredentials.setCaCert(AzureIotHubUtil.getDefaultCaCert()); - } - } - return credentials.initSslContext(); - } - -// @Override -// public void configure(MqttClientConfig config) { -// config.setProtocolVersion(MqttVersion.MQTT_3_1_1); -// config.setUsername(AzureIotHubUtil.buildUsername(mqttNodeConfiguration.getHost(), config.getClientId())); -// if (credentials instanceof AzureIotHubSasCredentials) { -// AzureIotHubSasCredentials sasCredentials = (AzureIotHubSasCredentials) credentials; -// config.setPassword(AzureIotHubUtil.buildSasToken(mqttNodeConfiguration.getHost(), sasCredentials.getSasKey())); -// } -// } - }); - + } this.mqttClient = initClient(ctx); } catch (Exception e) { throw new TbNodeException(e); } } + + protected void prepareMqttClientConfig(MqttClientConfig config) throws SSLException { + config.setProtocolVersion(MqttVersion.MQTT_3_1_1); + config.setUsername(AzureIotHubUtil.buildUsername(mqttNodeConfiguration.getHost(), config.getClientId())); + ClientCredentials credentials = mqttNodeConfiguration.getCredentials(); + if (CredentialsType.SAS == credentials.getType()) { + config.setPassword(AzureIotHubUtil.buildSasToken(mqttNodeConfiguration.getHost(), ((AzureIotHubSasCredentials) credentials).getSasKey())); + } + } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java index a2921029bc..17dc6b5bce 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java @@ -35,6 +35,7 @@ import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.http.client.HttpComponentsAsyncClientHttpRequestFactory; import org.springframework.http.client.Netty4ClientHttpRequestFactory; +import org.springframework.http.client.SimpleClientHttpRequestFactory; import org.springframework.util.StringUtils; import org.springframework.util.concurrent.ListenableFuture; import org.springframework.util.concurrent.ListenableFutureCallback; @@ -134,6 +135,9 @@ public class TbHttpClient { requestFactory.setReadTimeout(config.getReadTimeoutMs()); httpClient = new AsyncRestTemplate(requestFactory); } else if (config.isUseSimpleClientHttpFactory()) { + if (CredentialsType.CERT_PEM == config.getCredentials().getType()) { + throw new TbNodeException("Simple HTTP Factory does not support CERT PEM credentials!"); + } httpClient = new AsyncRestTemplate(); } else { this.eventLoopGroup = new NioEventLoopGroup(); @@ -231,7 +235,13 @@ public class TbHttpClient { private HttpHeaders prepareHeaders(TbMsgMetaData metaData) { HttpHeaders headers = new HttpHeaders(); config.getHeaders().forEach((k, v) -> headers.add(TbNodeUtils.processPattern(k, metaData), TbNodeUtils.processPattern(v, metaData))); - getBasicAuthHeaderValue(config.getCredentials()).ifPresent(authString -> headers.add("Authorization", authString)); + ClientCredentials credentials = config.getCredentials(); + if (CredentialsType.BASIC == credentials.getType()) { + BasicCredentials basicCredentials = (BasicCredentials) credentials; + String authString = basicCredentials.getUsername() + ":" + basicCredentials.getPassword(); + String encodedAuthString = new String(Base64.encodeBase64(authString.getBytes(StandardCharsets.UTF_8))); + headers.add("Authorization", "Basic " + encodedAuthString); + } return headers; } @@ -266,13 +276,4 @@ public class TbHttpClient { } } - public static Optional getBasicAuthHeaderValue(ClientCredentials credentials) { - if (CredentialsType.BASIC == credentials.getType()) { - BasicCredentials basicCredentials = (BasicCredentials) credentials; - String authString = basicCredentials.getUsername() + ":" + basicCredentials.getPassword(); - String encodedAuthString = new String(Base64.encodeBase64(authString.getBytes(StandardCharsets.UTF_8))); - return Optional.of("Basic " + encodedAuthString); - } - return Optional.empty(); - } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/credentials/BasicCredentialsTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/credentials/BasicCredentialsTest.java deleted file mode 100644 index 9230e39dc4..0000000000 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/credentials/BasicCredentialsTest.java +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright © 2016-2021 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.thingsboard.rule.engine.rest.credentials; - -import org.junit.Assert; -import org.junit.Test; -import org.thingsboard.rule.engine.credentials.BasicCredentials; -import org.thingsboard.rule.engine.rest.TbHttpClient; - -public class BasicCredentialsTest { - @Test - public void getBasicAuthHeaderValueTest() { - BasicCredentials credentials = new BasicCredentials(); - credentials.setUsername("testUser"); - credentials.setPassword("testPwd"); - String actualHeaderValue = TbHttpClient.getBasicAuthHeaderValue(credentials).get(); - String expectedHeaderValue = "Basic dGVzdFVzZXI6dGVzdFB3ZA=="; - - Assert.assertEquals(expectedHeaderValue, actualHeaderValue); - } -} From 4e3a7ed89785e44ad24befbf2c28c94fcb0e29d4 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Fri, 22 Jan 2021 18:33:51 +0200 Subject: [PATCH 063/249] Add overwriteActivityTime checkbox to device wizard. Update rule node ui. --- .../public/static/rulenode/rulenode-core-config.js | 2 +- .../wizard/device-wizard-dialog.component.html | 12 +++++++++--- .../wizard/device-wizard-dialog.component.ts | 2 ++ .../modules/home/pages/device/device.component.ts | 2 +- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js index 6d78132629..d8f3386b04 100644 --- a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js +++ b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js @@ -12,5 +12,5 @@ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - ***************************************************************************** */var g=function(e,t){return(g=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])})(e,t)};function y(e,t){function r(){this.constructor=e}g(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}function b(e,t,r,n){var a,o=arguments.length,i=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,r,n);else for(var l=e.length-1;l>=0;l--)(a=e[l])&&(i=(o<3?a(i):o>3?a(t,r,i):a(t,r))||i);return o>3&&i&&Object.defineProperty(t,r,i),i}function h(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}Object.create;function C(e){var t="function"==typeof Symbol&&Symbol.iterator,r=t&&e[t],n=0;if(r)return r.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}Object.create;var v,F=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.emptyConfigForm},r.prototype.onConfigurationSet=function(e){this.emptyConfigForm=this.fb.group({})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-node-empty-config",template:"
"}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),x=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return y(r,e),r.prototype.configForm=function(){return this.attributesConfigForm},r.prototype.onConfigurationSet=function(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]],notifyDevice:[!e||e.scope,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-attributes-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),T=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.timeseriesConfigForm},r.prototype.onConfigurationSet=function(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-timeseries-config",template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),q=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.rpcRequestConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rpc-request-config",template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),S=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.logConfigForm},r.prototype.onConfigurationSet=function(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.logConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-log-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),I=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.assignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),k=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.clearAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],alarmType:[e?e.alarmType:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-clear-alarm-config",template:'
\n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),N=function(e){function r(t,r,n,o){var i=e.call(this,t)||this;return i.store=t,i.fb=r,i.nodeScriptTestService=n,i.translate=o,i.alarmSeverities=Object.keys(a.AlarmSeverity),i.alarmSeverityTranslationMap=a.alarmSeverityTranslations,i.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],i}return y(r,e),r.prototype.configForm=function(){return this.createAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]]})},r.prototype.validatorTriggers=function(){return["useMessageAlarmData"]},r.prototype.updateValidators=function(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([i.Validators.required]),this.createAlarmConfigForm.get("severity").setValidators([i.Validators.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})},r.prototype.testScript=function(){var e=this,t=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.removeKey=function(e,t){var r=this.createAlarmConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.createAlarmConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.createAlarmConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.createAlarmConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-create-alarm-config",template:'
\n \n \n \n
\n \n
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n \n \n
\n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),V=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return y(r,e),r.prototype.configForm=function(){return this.createRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[i.Validators.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["entityType"]},r.prototype.updateValidators=function(e){var t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==a.EntityType.DEVICE&&t!==a.EntityType.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([i.Validators.required]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-create-relation-config",template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),E=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.msgDelayConfigForm},r.prototype.onConfigurationSet=function(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(1e5)]]})},r.prototype.validatorTriggers=function(){return["useMetadataPeriodInSecondsPatterns"]},r.prototype.updateValidators=function(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([i.Validators.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([i.Validators.required,i.Validators.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-msg-delay-config",template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),A=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return y(r,e),r.prototype.configForm=function(){return this.deleteRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["deleteForSingleEntity","entityType"]},r.prototype.updateValidators=function(e){var t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,r=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&r?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-delete-relation-config",template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),L=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.generatorConfigForm},r.prototype.onConfigurationSet=function(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[i.Validators.required,i.Validators.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[i.Validators.required,i.Validators.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.prepareInputConfig=function(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e},r.prototype.prepareOutputConfig=function(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e},r.prototype.testScript=function(){var e=this,t=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId).subscribe((function(t){t&&e.generatorConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-generator-config",template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent);!function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(v||(v={}));var M,P=new Map([[v.CUSTOMER,"tb.rulenode.originator-customer"],[v.TENANT,"tb.rulenode.originator-tenant"],[v.RELATED,"tb.rulenode.originator-related"],[v.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(M||(M={}));var R,w=new Map([[M.CIRCLE,"tb.rulenode.perimeter-circle"],[M.POLYGON,"tb.rulenode.perimeter-polygon"]]);!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(R||(R={}));var O,D=new Map([[R.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[R.SECONDS,"tb.rulenode.time-unit-seconds"],[R.MINUTES,"tb.rulenode.time-unit-minutes"],[R.HOURS,"tb.rulenode.time-unit-hours"],[R.DAYS,"tb.rulenode.time-unit-days"]]);!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(O||(O={}));var K,B=new Map([[O.METER,"tb.rulenode.range-unit-meter"],[O.KILOMETER,"tb.rulenode.range-unit-kilometer"],[O.FOOT,"tb.rulenode.range-unit-foot"],[O.MILE,"tb.rulenode.range-unit-mile"],[O.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(K||(K={}));var G,U,j,H=new Map([[K.TITLE,"tb.rulenode.entity-details-title"],[K.COUNTRY,"tb.rulenode.entity-details-country"],[K.STATE,"tb.rulenode.entity-details-state"],[K.ZIP,"tb.rulenode.entity-details-zip"],[K.ADDRESS,"tb.rulenode.entity-details-address"],[K.ADDRESS2,"tb.rulenode.entity-details-address2"],[K.PHONE,"tb.rulenode.entity-details-phone"],[K.EMAIL,"tb.rulenode.entity-details-email"],[K.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(G||(G={})),function(e){e.ASC="ASC",e.DESC="DESC"}(U||(U={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(j||(j={}));var z,$=new Map([[j.STANDARD,"tb.rulenode.sqs-queue-standard"],[j.FIFO,"tb.rulenode.sqs-queue-fifo"]]),Q=["anonymous","basic","cert.PEM"],_=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),W=["sas","cert.PEM"],J=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(z||(z={}));var Y=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],Z=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]),X=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=w,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=B,n.timeUnits=Object.keys(R),n.timeUnitsTranslationMap=D,n}return y(r,e),r.prototype.configForm=function(){return this.geoActionConfigForm},r.prototype.onConfigurationSet=function(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[i.Validators.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterType").setValidators([]):this.geoActionConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoActionConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoActionConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.msgCountConfigForm},r.prototype.onConfigurationSet=function(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[i.Validators.required,i.Validators.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-msg-count-config",template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.rpcReplyConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rpc-reply-config",template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.saveToCustomTableConfigForm},r.prototype.onConfigurationSet=function(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[i.Validators.required]],fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-custom-table-config",template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n \n \n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ne=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.translate=r,o.injector=n,o.fb=a,o.propagateChange=null,o.valueChangeSubscription=null,o}var a;return y(r,e),a=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){this.ngControl=this.injector.get(i.NgControl),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))},r.prototype.keyValsFormArray=function(){return this.kvListFormGroup.get("keyVals")},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t,r,n=this;this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();var a=[];if(e)try{for(var o=C(Object.keys(e)),l=o.next();!l.done;l=o.next()){var s=l.value;Object.prototype.hasOwnProperty.call(e,s)&&a.push(this.fb.group({key:[s,[i.Validators.required]],value:[e[s],[i.Validators.required]]}))}}catch(e){t={error:e}}finally{try{l&&!l.done&&(r=o.return)&&r.call(o)}finally{if(t)throw t.error}}this.kvListFormGroup.setControl("keyVals",this.fb.array(a)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((function(){n.updateModel()}))},r.prototype.removeKeyVal=function(e){this.kvListFormGroup.get("keyVals").removeAt(e)},r.prototype.addKeyVal=function(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[i.Validators.required]],value:["",[i.Validators.required]]}))},r.prototype.validate=function(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}},r.prototype.updateModel=function(){var e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{var t={};e.forEach((function(e){t[e.key]=e.value})),this.propagateChange(t)}},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:t.Injector},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",String)],r.prototype,"requiredText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"keyText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"keyRequiredText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"valText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"valRequiredText",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=a=b([t.Component({selector:"tb-kv-map-config",template:'
\n
\n {{ keyText }}\n {{ valText }}\n \n
\n
\n
\n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n \n
\n \n
\n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return a})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return a})),multi:!0}],styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:rgba(0,0,0,.54);font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}"]}),h("design:paramtypes",[o.Store,n.TranslateService,t.Injector,i.FormBuilder])],r)}(a.PageComponent),ae=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n.propagateChange=null,n}var n;return y(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[i.Validators.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((function(t){e.deviceRelationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=b([t.Component({selector:"tb-device-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-type
\n \n \n
device.device-types
\n \n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.propagateChange=null,n}var n;return y(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((function(t){e.relationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=b([t.Component({selector:"tb-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),ie=function(e){function r(t,r,n,o){var i,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.truncate=n,s.fb=o,s.placeholder="tb.rulenode.message-type",s.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],s.messageTypes=[],s.messageTypesList=[],s.searchText="",s.propagateChange=function(e){},s.messageTypeConfigForm=s.fb.group({messageType:[null]});try{for(var u=C(Object.keys(a.MessageType)),d=u.next();!d.done;d=u.next()){var p=d.value;s.messageTypesList.push({name:a.messageTypeNames.get(a.MessageType[p]),value:p})}}catch(e){i={error:e}}finally{try{d&&!d.done&&(l=u.return)&&l.call(u)}finally{if(i)throw i.error}}return s}var l;return y(r,e),l=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.ngOnInit=function(){var e=this;this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(t){return e.fetchMessageTypes(t)})),f.share())},r.prototype.ngAfterViewInit=function(){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t=this;this.searchText="",this.messageTypes.length=0,e&&e.forEach((function(e){var r=t.messageTypesList.find((function(t){return t.value===e}));r?t.messageTypes.push({name:r.name,value:r.value}):t.messageTypes.push({name:e,value:e})}))},r.prototype.displayMessageTypeFn=function(e){return e?e.name:void 0},r.prototype.textIsNotEmpty=function(e){return!!(e&&null!=e&&e.length>0)},r.prototype.createMessageType=function(e,t){e.preventDefault(),this.transformMessageType(t)},r.prototype.add=function(e){this.transformMessageType(e.value)},r.prototype.fetchMessageTypes=function(e){if(this.searchText=e,this.searchText&&this.searchText.length){var t=this.searchText.toUpperCase();return c.of(this.messageTypesList.filter((function(e){return e.name.toUpperCase().includes(t)})))}return c.of(this.messageTypesList)},r.prototype.transformMessageType=function(e){if((e||"").trim()){var t=null,r=e.trim(),n=this.messageTypesList.find((function(e){return e.name===r}));(t=n?{name:n.name,value:n.value}:{name:r,value:r})&&this.addMessageType(t)}this.clear("")},r.prototype.remove=function(e){var t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())},r.prototype.selected=function(e){this.addMessageType(e.option.value),this.clear("")},r.prototype.addMessageType=function(e){-1===this.messageTypes.findIndex((function(t){return t.value===e.value}))&&(this.messageTypes.push(e),this.updateModel())},r.prototype.onFocus=function(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((function(){t.messageTypeInput.nativeElement.blur(),t.messageTypeInput.nativeElement.focus()}),0)},r.prototype.updateModel=function(){var e=this.messageTypes.map((function(e){return e.value}));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:a.TruncatePipe},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),b([t.Input(),h("design:type",String)],r.prototype,"label",void 0),b([t.Input(),h("design:type",Object)],r.prototype,"placeholder",void 0),b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.ViewChild("chipList",{static:!1}),h("design:type",d.MatChipList)],r.prototype,"chipList",void 0),b([t.ViewChild("messageTypeAutocomplete",{static:!1}),h("design:type",p.MatAutocomplete)],r.prototype,"matAutocomplete",void 0),b([t.ViewChild("messageTypeInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"messageTypeInput",void 0),r=l=b([t.Component({selector:"tb-message-types-config",template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return l})),multi:!0}]}),h("design:paramtypes",[o.Store,n.TranslateService,a.TruncatePipe,i.FormBuilder])],r)}(a.PageComponent),le=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.subscriptions=[],n.allCredentialsTypes=Q,n.credentialsTypeTranslationsMap=_,n.propagateChange=null,n}var n;return y(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.credentialsConfigFormGroup=this.fb.group({type:[null,[i.Validators.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(f.distinctUntilChanged()).subscribe((function(){e.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((function(){e.credentialsTypeChanged()})))},r.prototype.ngOnDestroy=function(){this.subscriptions.forEach((function(e){return e.unsubscribe()}))},r.prototype.writeValue=function(e){s.isDefinedAndNotNull(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))},r.prototype.setDisabledState=function(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())},r.prototype.updateView=function(){var e=this.credentialsConfigFormGroup.value,t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.validate=function(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}},r.prototype.credentialsTypeChanged=function(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()},r.prototype.updateValidators=function(e){void 0===e&&(e=!1);var t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([i.Validators.required]),this.credentialsConfigFormGroup.get("password").setValidators([i.Validators.required]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(i.Validators.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})},r.prototype.requiredFilesSelected=function(e,t){return void 0===t&&(t=null),function(r){return t||(t=[Object.keys(r.controls)]),(null==r?void 0:r.controls)&&t.some((function(t){return t.every((function(t){return!e(r.controls[t])}))}))?null:{notAllRequiredFilesSelected:!0}}},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=b([t.Component({selector:"tb-credentials-config",template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n
\n
\n
\n
\n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),se=function(){function e(){}return e=b([t.NgModule({declarations:[ne,ae,oe,ie,le],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule],exports:[ne,ae,oe,ie,le]})],e)}(),me=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.unassignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-un-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ue=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.snsConfigForm},r.prototype.onConfigurationSet=function(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[i.Validators.required]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-sns-config",template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),de=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.sqsQueueType=j,n.sqsQueueTypes=Object.keys(j),n.sqsQueueTypeTranslationsMap=$,n}return y(r,e),r.prototype.configForm=function(){return this.sqsConfigForm},r.prototype.onConfigurationSet=function(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[i.Validators.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[i.Validators.required]],delaySeconds:[e?e.delaySeconds:null,[i.Validators.min(0),i.Validators.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-sqs-config",template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.pubSubConfigForm},r.prototype.onConfigurationSet=function(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[i.Validators.required]],topicName:[e?e.topicName:null,[i.Validators.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[i.Validators.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[i.Validators.required]],messageAttributes:[e?e.messageAttributes:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-pub-sub-config",template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.ackValues=["all","-1","0","1"],n.ToByteStandartCharsetTypesValues=Y,n.ToByteStandartCharsetTypeTranslationMap=Z,n}return y(r,e),r.prototype.configForm=function(){return this.kafkaConfigForm},r.prototype.onConfigurationSet=function(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],bootstrapServers:[e?e.bootstrapServers:null,[i.Validators.required]],retries:[e?e.retries:null,[i.Validators.min(0)]],batchSize:[e?e.batchSize:null,[i.Validators.min(0)]],linger:[e?e.linger:null,[i.Validators.min(0)]],bufferMemory:[e?e.bufferMemory:null,[i.Validators.min(0)]],acks:[e?e.acks:null,[i.Validators.required]],keySerializer:[e?e.keySerializer:null,[i.Validators.required]],valueSerializer:[e?e.valueSerializer:null,[i.Validators.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})},r.prototype.validatorTriggers=function(){return["addMetadataKeyValuesAsKafkaHeaders"]},r.prototype.updateValidators=function(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([i.Validators.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-kafka-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.mqttConfigForm},r.prototype.onConfigurationSet=function(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-mqtt-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n \n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],n}return y(r,e),r.prototype.configForm=function(){return this.rabbitMqConfigForm},r.prototype.onConfigurationSet=function(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[i.Validators.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[i.Validators.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rabbit-mq-config",template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ye=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.proxySchemes=["http","https"],n.httpRequestTypes=Object.keys(z),n}return y(r,e),r.prototype.configForm=function(){return this.restApiCallConfigForm},r.prototype.onConfigurationSet=function(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[i.Validators.required]],requestMethod:[e?e.requestMethod:null,[i.Validators.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[i.Validators.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})},r.prototype.validatorTriggers=function(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]},r.prototype.updateValidators=function(e){var t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,r=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,n=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;n&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(n?[i.Validators.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(n?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([i.Validators.min(0)])),r?this.restApiCallConfigForm.get("maxQueueSize").setValidators([i.Validators.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rest-api-call-config",template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n \n \n \n tb.rulenode.max-parallel-requests-count\n \n \n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.smtpProtocols=["smtp","smtps"],n.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"],n}return y(r,e),r.prototype.configForm=function(){return this.sendEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmtpSettings","enableProxy"]},r.prototype.updateValidators=function(e){var t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,r=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([i.Validators.required,i.Validators.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(r?[i.Validators.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(r?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-send-email-config",template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),he=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.serviceType=a.ServiceType.TB_RULE_ENGINE,n}return y(r,e),r.prototype.configForm=function(){return this.checkPointConfigForm},r.prototype.onConfigurationSet=function(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-check-point-config",template:'
\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allAzureIotHubCredentialsTypes=W,n.azureIotHubCredentialsTypeTranslationsMap=J,n}return y(r,e),r.prototype.configForm=function(){return this.azureIotHubConfigForm},r.prototype.onConfigurationSet=function(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[i.Validators.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[i.Validators.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})},r.prototype.prepareOutputConfig=function(e){var t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e},r.prototype.validatorTriggers=function(){return["credentials.type"]},r.prototype.updateValidators=function(e){var t=this.azureIotHubConfigForm.get("credentials"),r=t.get("type").value;switch(e&&t.reset({type:r},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),r){case"sas":t.get("sasKey").setValidators([i.Validators.required]);break;case"cert.PEM":t.get("privateKey").setValidators([i.Validators.required]),t.get("privateKeyFileName").setValidators([i.Validators.required]),t.get("cert").setValidators([i.Validators.required]),t.get("certFileName").setValidators([i.Validators.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-azure-iot-hub-config",template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.deviceProfile},r.prototype.onConfigurationSet=function(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,i.Validators.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,i.Validators.required]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-device-profile-config",template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.sendSmsConfigForm},r.prototype.onConfigurationSet=function(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[i.Validators.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[i.Validators.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmsSettings"]},r.prototype.updateValidators=function(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([i.Validators.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-send-sms-config",template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),xe=function(){function e(){}return e=b([t.NgModule({declarations:[x,T,q,S,I,k,N,V,E,A,L,X,ee,te,re,me,ue,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule,se],exports:[x,T,q,S,I,k,N,V,E,A,L,X,ee,te,re,me,ue,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe]})],e)}(),Te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.checkMessageConfigForm},r.prototype.onConfigurationSet=function(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})},r.prototype.validateConfig=function(){var e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0},r.prototype.removeMessageName=function(e){var t=this.checkMessageConfigForm.get("messageNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))},r.prototype.removeMetadataName=function(e){var t=this.checkMessageConfigForm.get("metadataNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))},r.prototype.addMessageName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("messageNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("messageNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.prototype.addMetadataName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("metadataNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("metadataNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-check-message-config",template:'
\n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),qe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.entitySearchDirection=Object.keys(a.EntitySearchDirection),n.entitySearchDirectionTranslationsMap=a.entitySearchDirectionTranslations,n}return y(r,e),r.prototype.configForm=function(){return this.checkRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],relationType:[e?e.relationType:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["checkForSingleEntity"]},r.prototype.updateValidators=function(e){var t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-check-relation-config",template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=w,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=B,n}return y(r,e),r.prototype.configForm=function(){return this.geoFilterConfigForm},r.prototype.onConfigurationSet=function(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterType").setValidators([]):this.geoFilterConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoFilterConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoFilterConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ie=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.messageTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-message-type-config",template:'
\n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allowedEntityTypes=[a.EntityType.DEVICE,a.EntityType.ASSET,a.EntityType.ENTITY_VIEW,a.EntityType.TENANT,a.EntityType.CUSTOMER,a.EntityType.USER,a.EntityType.DASHBOARD,a.EntityType.RULE_CHAIN,a.EntityType.RULE_NODE],n}return y(r,e),r.prototype.configForm=function(){return this.originatorTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-originator-type-config",template:'
\n \n \n \n
\n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ne=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-filter-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Ve=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.switchConfigForm},r.prototype.onConfigurationSet=function(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.switchConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-filter-node-switch-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Ee=function(e){function r(t,r,n){var o,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.fb=n,s.alarmStatusTranslationsMap=a.alarmStatusTranslations,s.alarmStatusList=[],s.searchText="",s.displayStatusFn=s.displayStatus.bind(s);try{for(var m=C(Object.keys(a.AlarmStatus)),u=m.next();!u.done;u=m.next()){var d=u.value;s.alarmStatusList.push(a.AlarmStatus[d])}}catch(e){o={error:e}}finally{try{u&&!u.done&&(l=m.return)&&l.call(m)}finally{if(o)throw o.error}}return s.statusFormControl=new i.FormControl(""),s.filteredAlarmStatus=s.statusFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return s.fetchAlarmStatus(e)})),f.share()),s}return y(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.alarmStatusConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[i.Validators.required]]})},r.prototype.displayStatus=function(e){return e?this.translate.instant(a.alarmStatusTranslations.get(e)):void 0},r.prototype.fetchAlarmStatus=function(e){var t=this,r=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){var n=this.searchText.toUpperCase();return c.of(r.filter((function(e){return t.translate.instant(a.alarmStatusTranslations.get(a.AlarmStatus[e])).toUpperCase().includes(n)})))}return c.of(r)},r.prototype.alarmStatusSelected=function(e){this.addAlarmStatus(e.option.value),this.clear("")},r.prototype.removeAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}},r.prototype.addAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))},r.prototype.getAlarmStatusList=function(){var e=this;return this.alarmStatusList.filter((function(t){return-1===e.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(t)}))},r.prototype.onAlarmStatusInputFocus=function(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.alarmStatusInput.nativeElement.blur(),t.alarmStatusInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},b([t.ViewChild("alarmStatusInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"alarmStatusInput",void 0),r=b([t.Component({selector:"tb-filter-node-check-alarm-status-config",template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n'}),h("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ae=function(){function e(){}return e=b([t.NgModule({declarations:[Te,qe,Se,Ie,ke,Ne,Ve,Ee],imports:[r.CommonModule,a.SharedModule,se],exports:[Te,qe,Se,Ie,ke,Ne,Ve,Ee]})],e)}(),Le=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.customerAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-customer-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Me=function(e){function r(t,r,n){var a,o,l=e.call(this,t)||this;l.store=t,l.translate=r,l.fb=n,l.entityDetailsTranslationsMap=H,l.entityDetailsList=[],l.searchText="",l.displayDetailsFn=l.displayDetails.bind(l);try{for(var s=C(Object.keys(K)),m=s.next();!m.done;m=s.next()){var u=m.value;l.entityDetailsList.push(K[u])}}catch(e){a={error:e}}finally{try{m&&!m.done&&(o=s.return)&&o.call(s)}finally{if(a)throw a.error}}return l.detailsFormControl=new i.FormControl(""),l.filteredEntityDetails=l.detailsFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return l.fetchEntityDetails(e)})),f.share()),l}return y(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.entityDetailsConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[i.Validators.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})},r.prototype.displayDetails=function(e){return e?this.translate.instant(H.get(e)):void 0},r.prototype.fetchEntityDetails=function(e){var t=this;if(this.searchText=e,this.searchText&&this.searchText.length){var r=this.searchText.toUpperCase();return c.of(this.entityDetailsList.filter((function(e){return t.translate.instant(H.get(K[e])).toUpperCase().includes(r)})))}return c.of(this.entityDetailsList)},r.prototype.detailsFieldSelected=function(e){this.addDetailsField(e.option.value),this.clear("")},r.prototype.removeDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}},r.prototype.addDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))},r.prototype.onEntityDetailsInputFocus=function(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.detailsInput.nativeElement.blur(),t.detailsInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},b([t.ViewChild("detailsInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"detailsInput",void 0),r=b([t.Component({selector:"tb-enrichment-node-entity-details-config",template:'
\n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-entity-details-matching\n
\n
\n
\n
\n
\n \n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
tb.rulenode.add-to-metadata-hint
\n
\n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}"]}),h("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.deviceAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[i.Validators.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.deviceAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.deviceAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.deviceAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.deviceAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-device-attributes-config",template:'
\n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.originatorAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.originatorAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.originatorAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.originatorAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.originatorAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-originator-attributes-config",template:'
\n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),we=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.originatorFieldsConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-originator-fields-config",template:'
\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n.fetchMode=G,n.fetchModes=Object.keys(G),n.samplingOrders=Object.keys(U),n.timeUnits=Object.keys(R),n.timeUnitsTranslationMap=D,n}return y(r,e),r.prototype.configForm=function(){return this.getTelemetryFromDatabaseConfigForm},r.prototype.onConfigurationSet=function(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],fetchMode:[e?e.fetchMode:null,[i.Validators.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchMode","useMetadataIntervalPatterns"]},r.prototype.updateValidators=function(e){var t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,r=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===G.ALL?(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([i.Validators.required,i.Validators.min(2),i.Validators.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),r?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([i.Validators.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})},r.prototype.removeKey=function(e,t){var r=this.getTelemetryFromDatabaseConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.getTelemetryFromDatabaseConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-get-telemetry-from-database",template:'
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
\n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
\n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-interval-patterns-hint
\n
\n
\n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),De=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.relatedAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[i.Validators.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-related-attributes-config",template:'
\n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.tenantAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-tenant-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Be=function(){function e(){}return e=b([t.NgModule({declarations:[Le,Me,Pe,Re,we,Oe,De,Ke],imports:[r.CommonModule,a.SharedModule,se],exports:[Le,Me,Pe,Re,we,Oe,De,Ke]})],e)}(),Ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.originatorSource=v,n.originatorSources=Object.keys(v),n.originatorSourceTranslationMap=P,n}return y(r,e),r.prototype.configForm=function(){return this.changeOriginatorConfigForm},r.prototype.onConfigurationSet=function(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[i.Validators.required]],relationsQuery:[e?e.relationsQuery:null,[]]})},r.prototype.validatorTriggers=function(){return["originatorSource"]},r.prototype.updateValidators=function(e){var t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===v.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([i.Validators.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-transformation-node-change-originator-config",template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ue=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-transformation-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),je=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.toEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[i.Validators.required]],toTemplate:[e?e.toTemplate:null,[i.Validators.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[i.Validators.required]],bodyTemplate:[e?e.bodyTemplate:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-transformation-node-to-email-config",template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),He=function(){function e(){}return e=b([t.NgModule({declarations:[Ge,Ue,je],imports:[r.CommonModule,a.SharedModule,se],exports:[Ge,Ue,je]})],e)}(),ze=function(){function e(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-name-pattern-hint":"Name pattern, use ${metaKeyName} to substitute variables from metadata","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-type-pattern-hint":"Type pattern, use ${metaKeyName} to substitute variables from metadata","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-name-pattern-hint":"Customer name pattern, use ${metaKeyName} to substitute variables from metadata","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","client-attributes-hint":"Client attributes, use ${metaKeyName} to substitute variables from metadata","shared-attributes":"Shared attributes","shared-attributes-hint":"Shared attributes, use ${metaKeyName} to substitute variables from metadata","server-attributes":"Server attributes","server-attributes-hint":"Server attributes, use ${metaKeyName} to substitute variables from metadata","notify-device":"Notify Device","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","latest-timeseries":"Latest timeseries","latest-timeseries-hint":"Latest timeseries, use ${metaKeyName} to substitute variables from metadata","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-hint":"Relation type pattern, use ${metaKeyName} to substitute variables from metadata","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use metadata period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds metadata pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","period-in-seconds-pattern-hint":"Period in seconds pattern, use ${metaKeyName} to substitute variables from metadata","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","from-template-hint":"From address template, use ${metaKeyName} to substitute variables from metadata","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":"Comma separated address list, use ${metaKeyName} to substitute variables from metadata","cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","subject-template-hint":"Mail subject template, use ${metaKeyName} to substitute variables from metadata","body-template":"Body Template","body-template-required":"Body Template is required","body-template-hint":"Mail body template, use ${metaKeyName} to substitute variables from metadata","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","endpoint-url-pattern-hint":"HTTP URL address pattern, use ${metaKeyName} to substitute variables from metadata","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":"Use ${metaKeyName} in header/value fields to substitute variables from metadata",header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required","mqtt-topic-pattern-hint":"MQTT topic pattern, use ${metaKeyName} to substitute variables from metadata",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","topic-arn-pattern-hint":"Topic ARN pattern, use ${metaKeyName} to substitute variables from metadata","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","queue-url-pattern-hint":"Queue URL pattern, use ${metaKeyName} to substitute variables from metadata","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":"Use ${metaKeyName} in name/value fields to substitute variables from metadata","connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file *","private-key":"Client private key file *",cert:"Client certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use metadata interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","start-interval-pattern-hint":"Start interval pattern, use ${metaKeyName} to substitute variables from metadata","end-interval-pattern-hint":"End interval pattern, use ${metaKeyName} to substitute variables from metadata","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":"Comma separated Phone Numbers, use ${metaKeyName} to substitute variables from metadata","sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","sms-message-template-hint":"SMS message template, use ${metaKeyName} to substitute variables from metadata","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-zip":"Zip","entity-details-address":"Address","entity-details-address2":"Address2","entity-details-additional_info":"Additional Info","entity-details-phone":"Phone","entity-details-email":"Email","add-to-metadata":"Add selected details to message metadata","add-to-metadata-hint":"If selected, adds the selected details keys to the message metadata instead of message data.","entity-details-list-empty":"No entity details selected.","no-entity-details-matching":"No entity details matching were found.","custom-table-name":"Custom table name","custom-table-name-required":"Table Name is required","custom-table-hint":"You should enter the table name without prefix 'cs_tb_'.","message-field":"Message field","message-field-required":"Message field is required.","table-col":"Table column","table-col-required":"Table column is required.","latitude-key-name":"Latitude key name","longitude-key-name":"Longitude key name","latitude-key-name-required":"Latitude key name is required.","longitude-key-name-required":"Longitude key name is required.","fetch-perimeter-info-from-message-metadata":"Fetch perimeter information from message metadata","perimeter-circle":"Circle","perimeter-polygon":"Polygon","perimeter-type":"Perimeter type","circle-center-latitude":"Center latitude","circle-center-latitude-required":"Center latitude is required.","circle-center-longitude":"Center longitude","circle-center-longitude-required":"Center longitude is required.","range-unit-meter":"Meter","range-unit-kilometer":"Kilometer","range-unit-foot":"Foot","range-unit-mile":"Mile","range-unit-nautical-mile":"Nautical mile","range-units":"Range units",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].","min-inside-duration":"Minimal inside duration","min-inside-duration-value-required":"Minimal inside duration is required","min-inside-duration-time-unit":"Minimal inside duration time unit","min-outside-duration":"Minimal outside duration","min-outside-duration-value-required":"Minimal outside duration is required","min-outside-duration-time-unit":"Minimal outside duration time unit","tell-failure-if-absent":"Tell Failure","tell-failure-if-absent-hint":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"get-latest-value-with-ts":"Fetch Latest telemetry with Timestamp","get-latest-value-with-ts-hint":'If selected, latest telemetry values will be added to the outbound message metadata with timestamp, e.g: "temp": "{\\"ts\\":1574329385897,\\"value\\":42}"',"use-redis-queue":"Use redis queue for message persistence","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules"},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"}}},!0)}(e)}return e.ctorParameters=function(){return[{type:n.TranslateService}]},e=b([t.NgModule({declarations:[F],imports:[r.CommonModule,a.SharedModule],exports:[xe,Ae,Be,He,F]}),h("design:paramtypes",[n.TranslateService])],e)}();e.RuleNodeCoreConfigModule=ze,e.ɵa=F,e.ɵb=xe,e.ɵba=he,e.ɵbb=Ce,e.ɵbc=ve,e.ɵbd=Fe,e.ɵbe=se,e.ɵbf=ne,e.ɵbg=ae,e.ɵbh=oe,e.ɵbi=ie,e.ɵbj=le,e.ɵbk=Ae,e.ɵbl=Te,e.ɵbm=qe,e.ɵbn=Se,e.ɵbo=Ie,e.ɵbp=ke,e.ɵbq=Ne,e.ɵbr=Ve,e.ɵbs=Ee,e.ɵbt=Be,e.ɵbu=Le,e.ɵbv=Me,e.ɵbw=Pe,e.ɵbx=Re,e.ɵby=we,e.ɵbz=Oe,e.ɵc=x,e.ɵca=De,e.ɵcb=Ke,e.ɵcc=He,e.ɵcd=Ge,e.ɵce=Ue,e.ɵcf=je,e.ɵd=T,e.ɵe=q,e.ɵf=S,e.ɵg=I,e.ɵh=k,e.ɵi=N,e.ɵj=V,e.ɵk=E,e.ɵl=A,e.ɵm=L,e.ɵn=X,e.ɵo=ee,e.ɵp=te,e.ɵq=re,e.ɵr=me,e.ɵs=ue,e.ɵt=de,e.ɵu=pe,e.ɵv=ce,e.ɵw=fe,e.ɵx=ge,e.ɵy=ye,e.ɵz=be,Object.defineProperty(e,"__esModule",{value:!0})})); + ***************************************************************************** */var g=function(e,t){return(g=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])})(e,t)};function y(e,t){function r(){this.constructor=e}g(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}function b(e,t,r,n){var a,o=arguments.length,i=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,r,n);else for(var l=e.length-1;l>=0;l--)(a=e[l])&&(i=(o<3?a(i):o>3?a(t,r,i):a(t,r))||i);return o>3&&i&&Object.defineProperty(t,r,i),i}function h(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}Object.create;function C(e){var t="function"==typeof Symbol&&Symbol.iterator,r=t&&e[t],n=0;if(r)return r.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}Object.create;var v,F=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.emptyConfigForm},r.prototype.onConfigurationSet=function(e){this.emptyConfigForm=this.fb.group({})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-node-empty-config",template:"
"}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),x=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return y(r,e),r.prototype.configForm=function(){return this.attributesConfigForm},r.prototype.onConfigurationSet=function(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]],notifyDevice:[!e||e.scope,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-attributes-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),T=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.timeseriesConfigForm},r.prototype.onConfigurationSet=function(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-timeseries-config",template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),q=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.rpcRequestConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rpc-request-config",template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),S=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.logConfigForm},r.prototype.onConfigurationSet=function(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.logConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-log-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),I=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.assignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),k=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.clearAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],alarmType:[e?e.alarmType:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-clear-alarm-config",template:'
\n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),N=function(e){function r(t,r,n,o){var i=e.call(this,t)||this;return i.store=t,i.fb=r,i.nodeScriptTestService=n,i.translate=o,i.alarmSeverities=Object.keys(a.AlarmSeverity),i.alarmSeverityTranslationMap=a.alarmSeverityTranslations,i.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],i}return y(r,e),r.prototype.configForm=function(){return this.createAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]]})},r.prototype.validatorTriggers=function(){return["useMessageAlarmData"]},r.prototype.updateValidators=function(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([i.Validators.required]),this.createAlarmConfigForm.get("severity").setValidators([i.Validators.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})},r.prototype.testScript=function(){var e=this,t=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.removeKey=function(e,t){var r=this.createAlarmConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.createAlarmConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.createAlarmConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.createAlarmConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-create-alarm-config",template:'
\n \n \n \n
\n \n
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n \n \n
\n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),V=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return y(r,e),r.prototype.configForm=function(){return this.createRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[i.Validators.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["entityType"]},r.prototype.updateValidators=function(e){var t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==a.EntityType.DEVICE&&t!==a.EntityType.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([i.Validators.required]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-create-relation-config",template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),E=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.msgDelayConfigForm},r.prototype.onConfigurationSet=function(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(1e5)]]})},r.prototype.validatorTriggers=function(){return["useMetadataPeriodInSecondsPatterns"]},r.prototype.updateValidators=function(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([i.Validators.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([i.Validators.required,i.Validators.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-msg-delay-config",template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),A=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return y(r,e),r.prototype.configForm=function(){return this.deleteRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["deleteForSingleEntity","entityType"]},r.prototype.updateValidators=function(e){var t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,r=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&r?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-delete-relation-config",template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),L=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.generatorConfigForm},r.prototype.onConfigurationSet=function(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[i.Validators.required,i.Validators.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[i.Validators.required,i.Validators.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.prepareInputConfig=function(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e},r.prototype.prepareOutputConfig=function(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e},r.prototype.testScript=function(){var e=this,t=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId).subscribe((function(t){t&&e.generatorConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-generator-config",template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent);!function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(v||(v={}));var M,P=new Map([[v.CUSTOMER,"tb.rulenode.originator-customer"],[v.TENANT,"tb.rulenode.originator-tenant"],[v.RELATED,"tb.rulenode.originator-related"],[v.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(M||(M={}));var R,w=new Map([[M.CIRCLE,"tb.rulenode.perimeter-circle"],[M.POLYGON,"tb.rulenode.perimeter-polygon"]]);!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(R||(R={}));var O,D=new Map([[R.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[R.SECONDS,"tb.rulenode.time-unit-seconds"],[R.MINUTES,"tb.rulenode.time-unit-minutes"],[R.HOURS,"tb.rulenode.time-unit-hours"],[R.DAYS,"tb.rulenode.time-unit-days"]]);!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(O||(O={}));var K,B=new Map([[O.METER,"tb.rulenode.range-unit-meter"],[O.KILOMETER,"tb.rulenode.range-unit-kilometer"],[O.FOOT,"tb.rulenode.range-unit-foot"],[O.MILE,"tb.rulenode.range-unit-mile"],[O.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(K||(K={}));var G,U,j,H=new Map([[K.TITLE,"tb.rulenode.entity-details-title"],[K.COUNTRY,"tb.rulenode.entity-details-country"],[K.STATE,"tb.rulenode.entity-details-state"],[K.ZIP,"tb.rulenode.entity-details-zip"],[K.ADDRESS,"tb.rulenode.entity-details-address"],[K.ADDRESS2,"tb.rulenode.entity-details-address2"],[K.PHONE,"tb.rulenode.entity-details-phone"],[K.EMAIL,"tb.rulenode.entity-details-email"],[K.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(G||(G={})),function(e){e.ASC="ASC",e.DESC="DESC"}(U||(U={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(j||(j={}));var z,$=new Map([[j.STANDARD,"tb.rulenode.sqs-queue-standard"],[j.FIFO,"tb.rulenode.sqs-queue-fifo"]]),Q=["anonymous","basic","cert.PEM"],_=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),W=["sas","cert.PEM"],J=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(z||(z={}));var Y=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],Z=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]),X=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=w,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=B,n.timeUnits=Object.keys(R),n.timeUnitsTranslationMap=D,n}return y(r,e),r.prototype.configForm=function(){return this.geoActionConfigForm},r.prototype.onConfigurationSet=function(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[i.Validators.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterType").setValidators([]):this.geoActionConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoActionConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoActionConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.msgCountConfigForm},r.prototype.onConfigurationSet=function(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[i.Validators.required,i.Validators.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-msg-count-config",template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.rpcReplyConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rpc-reply-config",template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.saveToCustomTableConfigForm},r.prototype.onConfigurationSet=function(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[i.Validators.required]],fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-custom-table-config",template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n \n \n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ne=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.translate=r,o.injector=n,o.fb=a,o.propagateChange=null,o.valueChangeSubscription=null,o}var a;return y(r,e),a=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){this.ngControl=this.injector.get(i.NgControl),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))},r.prototype.keyValsFormArray=function(){return this.kvListFormGroup.get("keyVals")},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t,r,n=this;this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();var a=[];if(e)try{for(var o=C(Object.keys(e)),l=o.next();!l.done;l=o.next()){var s=l.value;Object.prototype.hasOwnProperty.call(e,s)&&a.push(this.fb.group({key:[s,[i.Validators.required]],value:[e[s],[i.Validators.required]]}))}}catch(e){t={error:e}}finally{try{l&&!l.done&&(r=o.return)&&r.call(o)}finally{if(t)throw t.error}}this.kvListFormGroup.setControl("keyVals",this.fb.array(a)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((function(){n.updateModel()}))},r.prototype.removeKeyVal=function(e){this.kvListFormGroup.get("keyVals").removeAt(e)},r.prototype.addKeyVal=function(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[i.Validators.required]],value:["",[i.Validators.required]]}))},r.prototype.validate=function(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}},r.prototype.updateModel=function(){var e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{var t={};e.forEach((function(e){t[e.key]=e.value})),this.propagateChange(t)}},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:t.Injector},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",String)],r.prototype,"requiredText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"keyText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"keyRequiredText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"valText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"valRequiredText",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=a=b([t.Component({selector:"tb-kv-map-config",template:'
\n
\n {{ keyText }}\n {{ valText }}\n \n
\n
\n
\n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n \n
\n \n
\n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return a})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return a})),multi:!0}],styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:rgba(0,0,0,.54);font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}"]}),h("design:paramtypes",[o.Store,n.TranslateService,t.Injector,i.FormBuilder])],r)}(a.PageComponent),ae=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n.propagateChange=null,n}var n;return y(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[i.Validators.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((function(t){e.deviceRelationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=b([t.Component({selector:"tb-device-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-type
\n \n \n
device.device-types
\n \n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.propagateChange=null,n}var n;return y(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((function(t){e.relationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=b([t.Component({selector:"tb-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),ie=function(e){function r(t,r,n,o){var i,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.truncate=n,s.fb=o,s.placeholder="tb.rulenode.message-type",s.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],s.messageTypes=[],s.messageTypesList=[],s.searchText="",s.propagateChange=function(e){},s.messageTypeConfigForm=s.fb.group({messageType:[null]});try{for(var u=C(Object.keys(a.MessageType)),d=u.next();!d.done;d=u.next()){var p=d.value;s.messageTypesList.push({name:a.messageTypeNames.get(a.MessageType[p]),value:p})}}catch(e){i={error:e}}finally{try{d&&!d.done&&(l=u.return)&&l.call(u)}finally{if(i)throw i.error}}return s}var l;return y(r,e),l=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.ngOnInit=function(){var e=this;this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(t){return e.fetchMessageTypes(t)})),f.share())},r.prototype.ngAfterViewInit=function(){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t=this;this.searchText="",this.messageTypes.length=0,e&&e.forEach((function(e){var r=t.messageTypesList.find((function(t){return t.value===e}));r?t.messageTypes.push({name:r.name,value:r.value}):t.messageTypes.push({name:e,value:e})}))},r.prototype.displayMessageTypeFn=function(e){return e?e.name:void 0},r.prototype.textIsNotEmpty=function(e){return!!(e&&null!=e&&e.length>0)},r.prototype.createMessageType=function(e,t){e.preventDefault(),this.transformMessageType(t)},r.prototype.add=function(e){this.transformMessageType(e.value)},r.prototype.fetchMessageTypes=function(e){if(this.searchText=e,this.searchText&&this.searchText.length){var t=this.searchText.toUpperCase();return c.of(this.messageTypesList.filter((function(e){return e.name.toUpperCase().includes(t)})))}return c.of(this.messageTypesList)},r.prototype.transformMessageType=function(e){if((e||"").trim()){var t=null,r=e.trim(),n=this.messageTypesList.find((function(e){return e.name===r}));(t=n?{name:n.name,value:n.value}:{name:r,value:r})&&this.addMessageType(t)}this.clear("")},r.prototype.remove=function(e){var t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())},r.prototype.selected=function(e){this.addMessageType(e.option.value),this.clear("")},r.prototype.addMessageType=function(e){-1===this.messageTypes.findIndex((function(t){return t.value===e.value}))&&(this.messageTypes.push(e),this.updateModel())},r.prototype.onFocus=function(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((function(){t.messageTypeInput.nativeElement.blur(),t.messageTypeInput.nativeElement.focus()}),0)},r.prototype.updateModel=function(){var e=this.messageTypes.map((function(e){return e.value}));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:a.TruncatePipe},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),b([t.Input(),h("design:type",String)],r.prototype,"label",void 0),b([t.Input(),h("design:type",Object)],r.prototype,"placeholder",void 0),b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.ViewChild("chipList",{static:!1}),h("design:type",d.MatChipList)],r.prototype,"chipList",void 0),b([t.ViewChild("messageTypeAutocomplete",{static:!1}),h("design:type",p.MatAutocomplete)],r.prototype,"matAutocomplete",void 0),b([t.ViewChild("messageTypeInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"messageTypeInput",void 0),r=l=b([t.Component({selector:"tb-message-types-config",template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return l})),multi:!0}]}),h("design:paramtypes",[o.Store,n.TranslateService,a.TruncatePipe,i.FormBuilder])],r)}(a.PageComponent),le=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.subscriptions=[],n.disableCertPemCredentials=!1,n.allCredentialsTypes=Q,n.credentialsTypeTranslationsMap=_,n.propagateChange=null,n}var n;return y(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.credentialsConfigFormGroup=this.fb.group({type:[null,[i.Validators.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(f.distinctUntilChanged()).subscribe((function(){e.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((function(){e.credentialsTypeChanged()})))},r.prototype.ngOnChanges=function(e){var t,r,n=this;try{for(var a=C(Object.keys(e)),o=a.next();!o.done;o=a.next()){var i=o.value,l=e[i];if(!l.firstChange&&l.currentValue!==l.previousValue)if(l.currentValue&&"disableCertPemCredentials"===i)"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((function(){n.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}catch(e){t={error:e}}finally{try{o&&!o.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}},r.prototype.ngOnDestroy=function(){this.subscriptions.forEach((function(e){return e.unsubscribe()}))},r.prototype.writeValue=function(e){s.isDefinedAndNotNull(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))},r.prototype.setDisabledState=function(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())},r.prototype.updateView=function(){var e=this.credentialsConfigFormGroup.value,t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.validate=function(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}},r.prototype.credentialsTypeChanged=function(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()},r.prototype.updateValidators=function(e){void 0===e&&(e=!1);var t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([i.Validators.required]),this.credentialsConfigFormGroup.get("password").setValidators([i.Validators.required]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(i.Validators.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})},r.prototype.requiredFilesSelected=function(e,t){return void 0===t&&(t=null),function(r){return t||(t=[Object.keys(r.controls)]),(null==r?void 0:r.controls)&&t.some((function(t){return t.every((function(t){return!e(r.controls[t])}))}))?null:{notAllRequiredFilesSelected:!0}}},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),b([t.Input(),h("design:type",Object)],r.prototype,"disableCertPemCredentials",void 0),r=n=b([t.Component({selector:"tb-credentials-config",template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n
\n
\n
\n
\n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),se=function(){function e(){}return e=b([t.NgModule({declarations:[ne,ae,oe,ie,le],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule],exports:[ne,ae,oe,ie,le]})],e)}(),me=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.unassignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-un-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ue=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.snsConfigForm},r.prototype.onConfigurationSet=function(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[i.Validators.required]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-sns-config",template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),de=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.sqsQueueType=j,n.sqsQueueTypes=Object.keys(j),n.sqsQueueTypeTranslationsMap=$,n}return y(r,e),r.prototype.configForm=function(){return this.sqsConfigForm},r.prototype.onConfigurationSet=function(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[i.Validators.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[i.Validators.required]],delaySeconds:[e?e.delaySeconds:null,[i.Validators.min(0),i.Validators.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-sqs-config",template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.pubSubConfigForm},r.prototype.onConfigurationSet=function(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[i.Validators.required]],topicName:[e?e.topicName:null,[i.Validators.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[i.Validators.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[i.Validators.required]],messageAttributes:[e?e.messageAttributes:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-pub-sub-config",template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.ackValues=["all","-1","0","1"],n.ToByteStandartCharsetTypesValues=Y,n.ToByteStandartCharsetTypeTranslationMap=Z,n}return y(r,e),r.prototype.configForm=function(){return this.kafkaConfigForm},r.prototype.onConfigurationSet=function(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],bootstrapServers:[e?e.bootstrapServers:null,[i.Validators.required]],retries:[e?e.retries:null,[i.Validators.min(0)]],batchSize:[e?e.batchSize:null,[i.Validators.min(0)]],linger:[e?e.linger:null,[i.Validators.min(0)]],bufferMemory:[e?e.bufferMemory:null,[i.Validators.min(0)]],acks:[e?e.acks:null,[i.Validators.required]],keySerializer:[e?e.keySerializer:null,[i.Validators.required]],valueSerializer:[e?e.valueSerializer:null,[i.Validators.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})},r.prototype.validatorTriggers=function(){return["addMetadataKeyValuesAsKafkaHeaders"]},r.prototype.updateValidators=function(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([i.Validators.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-kafka-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.mqttConfigForm},r.prototype.onConfigurationSet=function(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-mqtt-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n \n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],n}return y(r,e),r.prototype.configForm=function(){return this.rabbitMqConfigForm},r.prototype.onConfigurationSet=function(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[i.Validators.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[i.Validators.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rabbit-mq-config",template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ye=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.proxySchemes=["http","https"],n.httpRequestTypes=Object.keys(z),n}return y(r,e),r.prototype.configForm=function(){return this.restApiCallConfigForm},r.prototype.onConfigurationSet=function(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[i.Validators.required]],requestMethod:[e?e.requestMethod:null,[i.Validators.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[i.Validators.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})},r.prototype.validatorTriggers=function(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]},r.prototype.updateValidators=function(e){var t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,r=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,n=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;n&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(n?[i.Validators.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(n?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([i.Validators.min(0)])),r?this.restApiCallConfigForm.get("maxQueueSize").setValidators([i.Validators.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rest-api-call-config",template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n \n \n \n tb.rulenode.max-parallel-requests-count\n \n \n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.smtpProtocols=["smtp","smtps"],n.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"],n}return y(r,e),r.prototype.configForm=function(){return this.sendEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmtpSettings","enableProxy"]},r.prototype.updateValidators=function(e){var t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,r=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([i.Validators.required,i.Validators.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(r?[i.Validators.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(r?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-send-email-config",template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),he=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.serviceType=a.ServiceType.TB_RULE_ENGINE,n}return y(r,e),r.prototype.configForm=function(){return this.checkPointConfigForm},r.prototype.onConfigurationSet=function(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-check-point-config",template:'
\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allAzureIotHubCredentialsTypes=W,n.azureIotHubCredentialsTypeTranslationsMap=J,n}return y(r,e),r.prototype.configForm=function(){return this.azureIotHubConfigForm},r.prototype.onConfigurationSet=function(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[i.Validators.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[i.Validators.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})},r.prototype.prepareOutputConfig=function(e){var t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e},r.prototype.validatorTriggers=function(){return["credentials.type"]},r.prototype.updateValidators=function(e){var t=this.azureIotHubConfigForm.get("credentials"),r=t.get("type").value;switch(e&&t.reset({type:r},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),r){case"sas":t.get("sasKey").setValidators([i.Validators.required]);break;case"cert.PEM":t.get("privateKey").setValidators([i.Validators.required]),t.get("privateKeyFileName").setValidators([i.Validators.required]),t.get("cert").setValidators([i.Validators.required]),t.get("certFileName").setValidators([i.Validators.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-azure-iot-hub-config",template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.deviceProfile},r.prototype.onConfigurationSet=function(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,i.Validators.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,i.Validators.required]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-device-profile-config",template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.sendSmsConfigForm},r.prototype.onConfigurationSet=function(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[i.Validators.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[i.Validators.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmsSettings"]},r.prototype.updateValidators=function(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([i.Validators.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-send-sms-config",template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),xe=function(){function e(){}return e=b([t.NgModule({declarations:[x,T,q,S,I,k,N,V,E,A,L,X,ee,te,re,me,ue,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule,se],exports:[x,T,q,S,I,k,N,V,E,A,L,X,ee,te,re,me,ue,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe]})],e)}(),Te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.checkMessageConfigForm},r.prototype.onConfigurationSet=function(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})},r.prototype.validateConfig=function(){var e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0},r.prototype.removeMessageName=function(e){var t=this.checkMessageConfigForm.get("messageNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))},r.prototype.removeMetadataName=function(e){var t=this.checkMessageConfigForm.get("metadataNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))},r.prototype.addMessageName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("messageNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("messageNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.prototype.addMetadataName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("metadataNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("metadataNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-check-message-config",template:'
\n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),qe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.entitySearchDirection=Object.keys(a.EntitySearchDirection),n.entitySearchDirectionTranslationsMap=a.entitySearchDirectionTranslations,n}return y(r,e),r.prototype.configForm=function(){return this.checkRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],relationType:[e?e.relationType:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["checkForSingleEntity"]},r.prototype.updateValidators=function(e){var t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-check-relation-config",template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=w,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=B,n}return y(r,e),r.prototype.configForm=function(){return this.geoFilterConfigForm},r.prototype.onConfigurationSet=function(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterType").setValidators([]):this.geoFilterConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoFilterConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoFilterConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ie=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.messageTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-message-type-config",template:'
\n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allowedEntityTypes=[a.EntityType.DEVICE,a.EntityType.ASSET,a.EntityType.ENTITY_VIEW,a.EntityType.TENANT,a.EntityType.CUSTOMER,a.EntityType.USER,a.EntityType.DASHBOARD,a.EntityType.RULE_CHAIN,a.EntityType.RULE_NODE],n}return y(r,e),r.prototype.configForm=function(){return this.originatorTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-originator-type-config",template:'
\n \n \n \n
\n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ne=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-filter-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Ve=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.switchConfigForm},r.prototype.onConfigurationSet=function(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.switchConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-filter-node-switch-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Ee=function(e){function r(t,r,n){var o,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.fb=n,s.alarmStatusTranslationsMap=a.alarmStatusTranslations,s.alarmStatusList=[],s.searchText="",s.displayStatusFn=s.displayStatus.bind(s);try{for(var m=C(Object.keys(a.AlarmStatus)),u=m.next();!u.done;u=m.next()){var d=u.value;s.alarmStatusList.push(a.AlarmStatus[d])}}catch(e){o={error:e}}finally{try{u&&!u.done&&(l=m.return)&&l.call(m)}finally{if(o)throw o.error}}return s.statusFormControl=new i.FormControl(""),s.filteredAlarmStatus=s.statusFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return s.fetchAlarmStatus(e)})),f.share()),s}return y(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.alarmStatusConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[i.Validators.required]]})},r.prototype.displayStatus=function(e){return e?this.translate.instant(a.alarmStatusTranslations.get(e)):void 0},r.prototype.fetchAlarmStatus=function(e){var t=this,r=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){var n=this.searchText.toUpperCase();return c.of(r.filter((function(e){return t.translate.instant(a.alarmStatusTranslations.get(a.AlarmStatus[e])).toUpperCase().includes(n)})))}return c.of(r)},r.prototype.alarmStatusSelected=function(e){this.addAlarmStatus(e.option.value),this.clear("")},r.prototype.removeAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}},r.prototype.addAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))},r.prototype.getAlarmStatusList=function(){var e=this;return this.alarmStatusList.filter((function(t){return-1===e.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(t)}))},r.prototype.onAlarmStatusInputFocus=function(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.alarmStatusInput.nativeElement.blur(),t.alarmStatusInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},b([t.ViewChild("alarmStatusInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"alarmStatusInput",void 0),r=b([t.Component({selector:"tb-filter-node-check-alarm-status-config",template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n'}),h("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ae=function(){function e(){}return e=b([t.NgModule({declarations:[Te,qe,Se,Ie,ke,Ne,Ve,Ee],imports:[r.CommonModule,a.SharedModule,se],exports:[Te,qe,Se,Ie,ke,Ne,Ve,Ee]})],e)}(),Le=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.customerAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-customer-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Me=function(e){function r(t,r,n){var a,o,l=e.call(this,t)||this;l.store=t,l.translate=r,l.fb=n,l.entityDetailsTranslationsMap=H,l.entityDetailsList=[],l.searchText="",l.displayDetailsFn=l.displayDetails.bind(l);try{for(var s=C(Object.keys(K)),m=s.next();!m.done;m=s.next()){var u=m.value;l.entityDetailsList.push(K[u])}}catch(e){a={error:e}}finally{try{m&&!m.done&&(o=s.return)&&o.call(s)}finally{if(a)throw a.error}}return l.detailsFormControl=new i.FormControl(""),l.filteredEntityDetails=l.detailsFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return l.fetchEntityDetails(e)})),f.share()),l}return y(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.entityDetailsConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[i.Validators.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})},r.prototype.displayDetails=function(e){return e?this.translate.instant(H.get(e)):void 0},r.prototype.fetchEntityDetails=function(e){var t=this;if(this.searchText=e,this.searchText&&this.searchText.length){var r=this.searchText.toUpperCase();return c.of(this.entityDetailsList.filter((function(e){return t.translate.instant(H.get(K[e])).toUpperCase().includes(r)})))}return c.of(this.entityDetailsList)},r.prototype.detailsFieldSelected=function(e){this.addDetailsField(e.option.value),this.clear("")},r.prototype.removeDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}},r.prototype.addDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))},r.prototype.onEntityDetailsInputFocus=function(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.detailsInput.nativeElement.blur(),t.detailsInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},b([t.ViewChild("detailsInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"detailsInput",void 0),r=b([t.Component({selector:"tb-enrichment-node-entity-details-config",template:'
\n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-entity-details-matching\n
\n
\n
\n
\n
\n \n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
tb.rulenode.add-to-metadata-hint
\n
\n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}"]}),h("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.deviceAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[i.Validators.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.deviceAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.deviceAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.deviceAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.deviceAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-device-attributes-config",template:'
\n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.originatorAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.originatorAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.originatorAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.originatorAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.originatorAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-originator-attributes-config",template:'
\n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),we=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.originatorFieldsConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-originator-fields-config",template:'
\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n.fetchMode=G,n.fetchModes=Object.keys(G),n.samplingOrders=Object.keys(U),n.timeUnits=Object.keys(R),n.timeUnitsTranslationMap=D,n}return y(r,e),r.prototype.configForm=function(){return this.getTelemetryFromDatabaseConfigForm},r.prototype.onConfigurationSet=function(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],fetchMode:[e?e.fetchMode:null,[i.Validators.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchMode","useMetadataIntervalPatterns"]},r.prototype.updateValidators=function(e){var t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,r=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===G.ALL?(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([i.Validators.required,i.Validators.min(2),i.Validators.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),r?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([i.Validators.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})},r.prototype.removeKey=function(e,t){var r=this.getTelemetryFromDatabaseConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.getTelemetryFromDatabaseConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-get-telemetry-from-database",template:'
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
\n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
\n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-interval-patterns-hint
\n
\n
\n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),De=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.relatedAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[i.Validators.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-related-attributes-config",template:'
\n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.tenantAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-tenant-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Be=function(){function e(){}return e=b([t.NgModule({declarations:[Le,Me,Pe,Re,we,Oe,De,Ke],imports:[r.CommonModule,a.SharedModule,se],exports:[Le,Me,Pe,Re,we,Oe,De,Ke]})],e)}(),Ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.originatorSource=v,n.originatorSources=Object.keys(v),n.originatorSourceTranslationMap=P,n}return y(r,e),r.prototype.configForm=function(){return this.changeOriginatorConfigForm},r.prototype.onConfigurationSet=function(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[i.Validators.required]],relationsQuery:[e?e.relationsQuery:null,[]]})},r.prototype.validatorTriggers=function(){return["originatorSource"]},r.prototype.updateValidators=function(e){var t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===v.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([i.Validators.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-transformation-node-change-originator-config",template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ue=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-transformation-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),je=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.toEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[i.Validators.required]],toTemplate:[e?e.toTemplate:null,[i.Validators.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[i.Validators.required]],bodyTemplate:[e?e.bodyTemplate:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-transformation-node-to-email-config",template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),He=function(){function e(){}return e=b([t.NgModule({declarations:[Ge,Ue,je],imports:[r.CommonModule,a.SharedModule,se],exports:[Ge,Ue,je]})],e)}(),ze=function(){function e(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-name-pattern-hint":"Name pattern, use ${metaKeyName} to substitute variables from metadata","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-type-pattern-hint":"Type pattern, use ${metaKeyName} to substitute variables from metadata","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-name-pattern-hint":"Customer name pattern, use ${metaKeyName} to substitute variables from metadata","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","client-attributes-hint":"Client attributes, use ${metaKeyName} to substitute variables from metadata","shared-attributes":"Shared attributes","shared-attributes-hint":"Shared attributes, use ${metaKeyName} to substitute variables from metadata","server-attributes":"Server attributes","server-attributes-hint":"Server attributes, use ${metaKeyName} to substitute variables from metadata","notify-device":"Notify Device","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","latest-timeseries":"Latest timeseries","latest-timeseries-hint":"Latest timeseries, use ${metaKeyName} to substitute variables from metadata","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-hint":"Relation type pattern, use ${metaKeyName} to substitute variables from metadata","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use metadata period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds metadata pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","period-in-seconds-pattern-hint":"Period in seconds pattern, use ${metaKeyName} to substitute variables from metadata","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","from-template-hint":"From address template, use ${metaKeyName} to substitute variables from metadata","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":"Comma separated address list, use ${metaKeyName} to substitute variables from metadata","cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","subject-template-hint":"Mail subject template, use ${metaKeyName} to substitute variables from metadata","body-template":"Body Template","body-template-required":"Body Template is required","body-template-hint":"Mail body template, use ${metaKeyName} to substitute variables from metadata","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","endpoint-url-pattern-hint":"HTTP URL address pattern, use ${metaKeyName} to substitute variables from metadata","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":"Use ${metaKeyName} in header/value fields to substitute variables from metadata",header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required","mqtt-topic-pattern-hint":"MQTT topic pattern, use ${metaKeyName} to substitute variables from metadata",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","topic-arn-pattern-hint":"Topic ARN pattern, use ${metaKeyName} to substitute variables from metadata","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","queue-url-pattern-hint":"Queue URL pattern, use ${metaKeyName} to substitute variables from metadata","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":"Use ${metaKeyName} in name/value fields to substitute variables from metadata","connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file *","private-key":"Client private key file *",cert:"Client certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use metadata interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","start-interval-pattern-hint":"Start interval pattern, use ${metaKeyName} to substitute variables from metadata","end-interval-pattern-hint":"End interval pattern, use ${metaKeyName} to substitute variables from metadata","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":"Comma separated Phone Numbers, use ${metaKeyName} to substitute variables from metadata","sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","sms-message-template-hint":"SMS message template, use ${metaKeyName} to substitute variables from metadata","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-zip":"Zip","entity-details-address":"Address","entity-details-address2":"Address2","entity-details-additional_info":"Additional Info","entity-details-phone":"Phone","entity-details-email":"Email","add-to-metadata":"Add selected details to message metadata","add-to-metadata-hint":"If selected, adds the selected details keys to the message metadata instead of message data.","entity-details-list-empty":"No entity details selected.","no-entity-details-matching":"No entity details matching were found.","custom-table-name":"Custom table name","custom-table-name-required":"Table Name is required","custom-table-hint":"You should enter the table name without prefix 'cs_tb_'.","message-field":"Message field","message-field-required":"Message field is required.","table-col":"Table column","table-col-required":"Table column is required.","latitude-key-name":"Latitude key name","longitude-key-name":"Longitude key name","latitude-key-name-required":"Latitude key name is required.","longitude-key-name-required":"Longitude key name is required.","fetch-perimeter-info-from-message-metadata":"Fetch perimeter information from message metadata","perimeter-circle":"Circle","perimeter-polygon":"Polygon","perimeter-type":"Perimeter type","circle-center-latitude":"Center latitude","circle-center-latitude-required":"Center latitude is required.","circle-center-longitude":"Center longitude","circle-center-longitude-required":"Center longitude is required.","range-unit-meter":"Meter","range-unit-kilometer":"Kilometer","range-unit-foot":"Foot","range-unit-mile":"Mile","range-unit-nautical-mile":"Nautical mile","range-units":"Range units",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].","min-inside-duration":"Minimal inside duration","min-inside-duration-value-required":"Minimal inside duration is required","min-inside-duration-time-unit":"Minimal inside duration time unit","min-outside-duration":"Minimal outside duration","min-outside-duration-value-required":"Minimal outside duration is required","min-outside-duration-time-unit":"Minimal outside duration time unit","tell-failure-if-absent":"Tell Failure","tell-failure-if-absent-hint":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"get-latest-value-with-ts":"Fetch Latest telemetry with Timestamp","get-latest-value-with-ts-hint":'If selected, latest telemetry values will be added to the outbound message metadata with timestamp, e.g: "temp": "{\\"ts\\":1574329385897,\\"value\\":42}"',"use-redis-queue":"Use redis queue for message persistence","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules"},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"}}},!0)}(e)}return e.ctorParameters=function(){return[{type:n.TranslateService}]},e=b([t.NgModule({declarations:[F],imports:[r.CommonModule,a.SharedModule],exports:[xe,Ae,Be,He,F]}),h("design:paramtypes",[n.TranslateService])],e)}();e.RuleNodeCoreConfigModule=ze,e.ɵa=F,e.ɵb=xe,e.ɵba=he,e.ɵbb=Ce,e.ɵbc=ve,e.ɵbd=Fe,e.ɵbe=se,e.ɵbf=ne,e.ɵbg=ae,e.ɵbh=oe,e.ɵbi=ie,e.ɵbj=le,e.ɵbk=Ae,e.ɵbl=Te,e.ɵbm=qe,e.ɵbn=Se,e.ɵbo=Ie,e.ɵbp=ke,e.ɵbq=Ne,e.ɵbr=Ve,e.ɵbs=Ee,e.ɵbt=Be,e.ɵbu=Le,e.ɵbv=Me,e.ɵbw=Pe,e.ɵbx=Re,e.ɵby=we,e.ɵbz=Oe,e.ɵc=x,e.ɵca=De,e.ɵcb=Ke,e.ɵcc=He,e.ɵcd=Ge,e.ɵce=Ue,e.ɵcf=je,e.ɵd=T,e.ɵe=q,e.ɵf=S,e.ɵg=I,e.ɵh=k,e.ɵi=N,e.ɵj=V,e.ɵk=E,e.ɵl=A,e.ɵm=L,e.ɵn=X,e.ɵo=ee,e.ɵp=te,e.ɵq=re,e.ɵr=me,e.ɵs=ue,e.ɵt=de,e.ɵu=pe,e.ɵv=ce,e.ɵw=fe,e.ɵx=ge,e.ɵy=ye,e.ɵz=be,Object.defineProperty(e,"__esModule",{value:!0})})); //# sourceMappingURL=rulenode-core-config.umd.min.js.map \ No newline at end of file diff --git a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html index fbebf66d4c..245cb6503b 100644 --- a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html @@ -108,9 +108,15 @@
- - {{ 'device.is-gateway' | translate }} - +
+ + {{ 'device.is-gateway' | translate }} + + + {{ 'device.overwrite-activity-time' | translate }} + +
device.description diff --git a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts index 66f115af93..593d32e2ff 100644 --- a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts @@ -108,6 +108,7 @@ export class DeviceWizardDialogComponent extends name: ['', Validators.required], label: [''], gateway: [false], + overwriteActivityTime: [false], transportType: [DeviceTransportType.DEFAULT, Validators.required], addProfileType: [0], deviceProfileId: [null, Validators.required], @@ -314,6 +315,7 @@ export class DeviceWizardDialogComponent extends deviceProfileId: profileId, additionalInfo: { gateway: this.deviceWizardFormGroup.get('gateway').value, + overwriteActivityTime: this.deviceWizardFormGroup.get('overwriteActivityTime').value, description: this.deviceWizardFormGroup.get('description').value }, customerId: null diff --git a/ui-ngx/src/app/modules/home/pages/device/device.component.ts b/ui-ngx/src/app/modules/home/pages/device/device.component.ts index 660b6341ca..261bb1eba5 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device.component.ts +++ b/ui-ngx/src/app/modules/home/pages/device/device.component.ts @@ -84,7 +84,7 @@ export class DeviceComponent extends EntityComponent { additionalInfo: this.fb.group( { gateway: [entity && entity.additionalInfo ? entity.additionalInfo.gateway : false], - overwriteActivityTime: [entity && entity.additionalInfo ? entity.additionalInfo.overwriteActivityTime: false], + overwriteActivityTime: [entity && entity.additionalInfo ? entity.additionalInfo.overwriteActivityTime : false], description: [entity && entity.additionalInfo ? entity.additionalInfo.description : ''], } ) From 317dfdbc42a206808172b357f5b60f66eaa363f6 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Fri, 22 Jan 2021 19:11:00 +0200 Subject: [PATCH 064/249] Lwm2m: front&back: refactoring add on the back ObjectIdFromTextSearch for search list models with filter by ObjectId --- .../service/lwm2m/LwM2MModelsRepository.java | 299 +++++++++--------- .../server/common/data/lwm2m/LwM2mObject.java | 4 - 2 files changed, 157 insertions(+), 146 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MModelsRepository.java b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MModelsRepository.java index 4057d613b9..1eb454c23a 100644 --- a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MModelsRepository.java +++ b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MModelsRepository.java @@ -35,7 +35,6 @@ import org.thingsboard.server.common.transport.lwm2m.LwM2MTransportConfigServer; import org.thingsboard.server.dao.service.Validator; import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode; -import java.lang.reflect.Field; import java.math.BigInteger; import java.security.AlgorithmParameters; import java.security.GeneralSecurityException; @@ -52,7 +51,9 @@ import java.security.spec.KeySpec; import java.util.ArrayList; import java.util.Comparator; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Predicate; +import java.util.stream.Collector; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -80,11 +81,13 @@ public class LwM2MModelsRepository { * if textSearch is null then it uses AllList from List) */ public List getLwm2mObjects(int[] objectIds, String textSearch, String sortProperty, String sortOrder) { - return getLwm2mObjects((objectIds != null && objectIds.length > 0 && textSearch != null && !textSearch.isEmpty()) ? + return getLwm2mObjects((objectIds.length > 0 && textSearch != null && !textSearch.isEmpty()) ? (ObjectModel element) -> IntStream.of(objectIds).anyMatch(x -> x == element.id) || element.name.contains(textSearch) : - (objectIds != null && objectIds.length > 0) ? + (objectIds.length > 0) ? (ObjectModel element) -> IntStream.of(objectIds).anyMatch(x -> x == element.id) : - (textSearch != null && !textSearch.isEmpty()) ? (ObjectModel element) -> element.name.contains(textSearch) : null, + (textSearch != null && !textSearch.isEmpty()) ? + (ObjectModel element) -> element.name.contains(textSearch) : + null, sortProperty, sortOrder); } @@ -118,177 +121,189 @@ public class LwM2MModelsRepository { lwM2mObject.setInstances(new LwM2mInstance[]{instance}); lwM2mObjects.add(lwM2mObject); }); - try { - Field field = LwM2mObject.class.getField(sortProperty); - } catch (NoSuchFieldException e) { - e.printStackTrace(); - } + return lwM2mObjects.size() > 1 ? this.sortList (lwM2mObjects, sortProperty, sortOrder) : lwM2mObjects; + } + + private List sortList (List lwM2mObjects, String sortProperty, String sortOrder) { switch (sortProperty) { case "name": switch (sortOrder) { case "ASC": - // ASC lwM2mObjects.sort((o1, o2) -> o1.getName().compareTo(o2.getName())); break; case "DESC": - // DESC lwM2mObjects.stream().sorted(Comparator.comparing(LwM2mObject::getName).reversed()); break; } case "id": switch (sortOrder) { case "ASC": - // ASC lwM2mObjects.sort((o1, o2) -> Long.compare(o1.getId(), o2.getId())); break; case "DESC": - // DESC lwM2mObjects.sort((o1, o2) -> Long.compare(o2.getId(), o1.getId())); } } return lwM2mObjects; } - /** - * @param tenantId - * @param pageLink - * @return List of LwM2mObject in PageData format - */ - public PageData findDeviceLwm2mObjects (TenantId tenantId, PageLink pageLink){ - log.trace("Executing findDeviceProfileInfos tenantId [{}], pageLink [{}]", tenantId, pageLink); - validateId(tenantId, INCORRECT_TENANT_ID + tenantId); - Validator.validatePageLink(pageLink); - return this.findLwm2mListObjects(pageLink); - } + /** + * @param tenantId + * @param pageLink + * @return List of LwM2mObject in PageData format + */ + public PageData findDeviceLwm2mObjects(TenantId tenantId, PageLink pageLink) { + log.trace("Executing findDeviceProfileInfos tenantId [{}], pageLink [{}]", tenantId, pageLink); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + Validator.validatePageLink(pageLink); + return this.findLwm2mListObjects(pageLink); + } - /** - * @param pageLink - * @return List of LwM2mObject in PageData format, filter == TextSearch - * PageNumber = 1, PageSize = List.size() - */ - public PageData findLwm2mListObjects (PageLink pageLink){ - PageImpl page = new PageImpl(getLwm2mObjects(null, pageLink.getTextSearch(), pageLink.getSortOrder().getProperty(), pageLink.getSortOrder().getDirection().name())); - PageData pageData = new PageData(page.getContent(), page.getTotalPages(), page.getTotalElements(), page.hasNext()); - return pageData; - } + /** + * @param pageLink + * @return List of LwM2mObject in PageData format, filter == TextSearch + * PageNumber = 1, PageSize = List.size() + */ + public PageData findLwm2mListObjects(PageLink pageLink) { + PageImpl page = new PageImpl(getLwm2mObjects(getObjectIdFromTextSearch(pageLink.getTextSearch()), pageLink.getTextSearch(), pageLink.getSortOrder().getProperty(), pageLink.getSortOrder().getDirection().name())); + PageData pageData = new PageData(page.getContent(), page.getTotalPages(), page.getTotalElements(), page.hasNext()); + return pageData; + } - /** - * @param securityMode - * @param bootstrapServerIs - * @return ServerSecurityConfig more value is default: Important - port, host, publicKey - */ - public ServerSecurityConfig getBootstrapSecurityInfo (String securityMode,boolean bootstrapServerIs){ - LwM2MSecurityMode lwM2MSecurityMode = LwM2MSecurityMode.fromSecurityMode(securityMode.toLowerCase()); - return getBootstrapServer(bootstrapServerIs, lwM2MSecurityMode); + /** + * Filter for id Object + * @param textSearch - + * @return - return Object id only first chartAt in textSearch + */ + private int[] getObjectIdFromTextSearch(String textSearch) { + String filtered = null; + if (textSearch !=null && !textSearch.isEmpty()) { + AtomicInteger a = new AtomicInteger(); + filtered = textSearch.chars () + .mapToObj(chr -> (char) chr) + .filter(i -> Character.isDigit(i) && textSearch.charAt(a.getAndIncrement()) == i) + .collect(Collector.of(StringBuilder::new, StringBuilder::append, StringBuilder::append, StringBuilder::toString)); } + return (filtered != null && !filtered.isEmpty()) ? new int[]{Integer.parseInt(filtered)} : new int[0]; + } - /** - * @param bootstrapServerIs - * @param mode - * @return ServerSecurityConfig more value is default: Important - port, host, publicKey - */ - private ServerSecurityConfig getBootstrapServer ( boolean bootstrapServerIs, LwM2MSecurityMode mode){ - ServerSecurityConfig bsServ = new ServerSecurityConfig(); - bsServ.setBootstrapServerIs(bootstrapServerIs); - if (bootstrapServerIs) { - bsServ.setServerId(contextBootStrap.getBootstrapServerId()); - switch (mode) { - case NO_SEC: - bsServ.setHost(contextBootStrap.getBootstrapHost()); - bsServ.setPort(contextBootStrap.getBootstrapPortNoSecPsk()); - bsServ.setServerPublicKey(""); - break; - case PSK: - bsServ.setHost(contextBootStrap.getBootstrapSecureHost()); - bsServ.setPort(contextBootStrap.getBootstrapSecurePortPsk()); - bsServ.setServerPublicKey(""); - break; - case RPK: - bsServ.setHost(contextBootStrap.getBootstrapSecureHost()); - bsServ.setPort(contextBootStrap.getBootstrapSecurePortRpk()); - bsServ.setServerPublicKey(getRPKPublicKey(this.contextBootStrap.getBootstrapPublicX(), this.contextBootStrap.getBootstrapPublicY())); - break; - case X509: - bsServ.setHost(contextBootStrap.getBootstrapSecureHost()); - bsServ.setPort(contextBootStrap.getBootstrapSecurePortX509()); - bsServ.setServerPublicKey(getServerPublicKeyX509(contextBootStrap.getBootstrapAlias())); - break; - default: - break; - } - } else { - bsServ.setServerId(contextServer.getServerId()); - switch (mode) { - case NO_SEC: - bsServ.setHost(contextServer.getServerHost()); - bsServ.setPort(contextServer.getServerPortNoSecPsk()); - bsServ.setServerPublicKey(""); - break; - case PSK: - bsServ.setHost(contextServer.getServerSecureHost()); - bsServ.setPort(contextServer.getServerPortPsk()); - bsServ.setServerPublicKey(""); - break; - case RPK: - bsServ.setHost(contextServer.getServerSecureHost()); - bsServ.setPort(contextServer.getServerPortRpk()); - bsServ.setServerPublicKey(getRPKPublicKey(this.contextServer.getServerPublicX(), this.contextServer.getServerPublicY())); - break; - case X509: - bsServ.setHost(contextServer.getServerSecureHost()); - bsServ.setPort(contextServer.getServerPortX509()); - bsServ.setServerPublicKey(getServerPublicKeyX509(contextServer.getServerAlias())); - break; - default: - break; - } + /** + * @param securityMode + * @param bootstrapServerIs + * @return ServerSecurityConfig more value is default: Important - port, host, publicKey + */ + public ServerSecurityConfig getBootstrapSecurityInfo(String securityMode, boolean bootstrapServerIs) { + LwM2MSecurityMode lwM2MSecurityMode = LwM2MSecurityMode.fromSecurityMode(securityMode.toLowerCase()); + return getBootstrapServer(bootstrapServerIs, lwM2MSecurityMode); + } + + /** + * @param bootstrapServerIs + * @param mode + * @return ServerSecurityConfig more value is default: Important - port, host, publicKey + */ + private ServerSecurityConfig getBootstrapServer(boolean bootstrapServerIs, LwM2MSecurityMode mode) { + ServerSecurityConfig bsServ = new ServerSecurityConfig(); + bsServ.setBootstrapServerIs(bootstrapServerIs); + if (bootstrapServerIs) { + bsServ.setServerId(contextBootStrap.getBootstrapServerId()); + switch (mode) { + case NO_SEC: + bsServ.setHost(contextBootStrap.getBootstrapHost()); + bsServ.setPort(contextBootStrap.getBootstrapPortNoSecPsk()); + bsServ.setServerPublicKey(""); + break; + case PSK: + bsServ.setHost(contextBootStrap.getBootstrapSecureHost()); + bsServ.setPort(contextBootStrap.getBootstrapSecurePortPsk()); + bsServ.setServerPublicKey(""); + break; + case RPK: + bsServ.setHost(contextBootStrap.getBootstrapSecureHost()); + bsServ.setPort(contextBootStrap.getBootstrapSecurePortRpk()); + bsServ.setServerPublicKey(getRPKPublicKey(this.contextBootStrap.getBootstrapPublicX(), this.contextBootStrap.getBootstrapPublicY())); + break; + case X509: + bsServ.setHost(contextBootStrap.getBootstrapSecureHost()); + bsServ.setPort(contextBootStrap.getBootstrapSecurePortX509()); + bsServ.setServerPublicKey(getServerPublicKeyX509(contextBootStrap.getBootstrapAlias())); + break; + default: + break; + } + } else { + bsServ.setServerId(contextServer.getServerId()); + switch (mode) { + case NO_SEC: + bsServ.setHost(contextServer.getServerHost()); + bsServ.setPort(contextServer.getServerPortNoSecPsk()); + bsServ.setServerPublicKey(""); + break; + case PSK: + bsServ.setHost(contextServer.getServerSecureHost()); + bsServ.setPort(contextServer.getServerPortPsk()); + bsServ.setServerPublicKey(""); + break; + case RPK: + bsServ.setHost(contextServer.getServerSecureHost()); + bsServ.setPort(contextServer.getServerPortRpk()); + bsServ.setServerPublicKey(getRPKPublicKey(this.contextServer.getServerPublicX(), this.contextServer.getServerPublicY())); + break; + case X509: + bsServ.setHost(contextServer.getServerSecureHost()); + bsServ.setPort(contextServer.getServerPortX509()); + bsServ.setServerPublicKey(getServerPublicKeyX509(contextServer.getServerAlias())); + break; + default: + break; } - return bsServ; } + return bsServ; + } - /** - * @param alias - * @return PublicKey format HexString or null - */ - private String getServerPublicKeyX509 (String alias){ - try { - X509Certificate serverCertificate = (X509Certificate) contextServer.getKeyStoreValue().getCertificate(alias); - return Hex.encodeHexString(serverCertificate.getEncoded()); - } catch (CertificateEncodingException | KeyStoreException e) { - e.printStackTrace(); - } - return null; + /** + * @param alias + * @return PublicKey format HexString or null + */ + private String getServerPublicKeyX509(String alias) { + try { + X509Certificate serverCertificate = (X509Certificate) contextServer.getKeyStoreValue().getCertificate(alias); + return Hex.encodeHexString(serverCertificate.getEncoded()); + } catch (CertificateEncodingException | KeyStoreException e) { + e.printStackTrace(); } + return null; + } - /** - * @param publicServerX - * @param publicServerY - * @return PublicKey format HexString or null - */ - private String getRPKPublicKey (String publicServerX, String publicServerY){ - try { - /** Get Elliptic Curve Parameter spec for secp256r1 */ - AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC"); - algoParameters.init(new ECGenParameterSpec("secp256r1")); - ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class); - if (publicServerX != null && !publicServerX.isEmpty() && publicServerY != null && !publicServerY.isEmpty()) { - /** Get point values */ - byte[] publicX = Hex.decodeHex(publicServerX.toCharArray()); - byte[] publicY = Hex.decodeHex(publicServerY.toCharArray()); - /** Create key specs */ - KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)), - parameterSpec); - /** Get keys */ - PublicKey publicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec); - if (publicKey != null && publicKey.getEncoded().length > 0) { - return Hex.encodeHexString(publicKey.getEncoded()); - } + /** + * @param publicServerX + * @param publicServerY + * @return PublicKey format HexString or null + */ + private String getRPKPublicKey(String publicServerX, String publicServerY) { + try { + /** Get Elliptic Curve Parameter spec for secp256r1 */ + AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC"); + algoParameters.init(new ECGenParameterSpec("secp256r1")); + ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class); + if (publicServerX != null && !publicServerX.isEmpty() && publicServerY != null && !publicServerY.isEmpty()) { + /** Get point values */ + byte[] publicX = Hex.decodeHex(publicServerX.toCharArray()); + byte[] publicY = Hex.decodeHex(publicServerY.toCharArray()); + /** Create key specs */ + KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)), + parameterSpec); + /** Get keys */ + PublicKey publicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec); + if (publicKey != null && publicKey.getEncoded().length > 0) { + return Hex.encodeHexString(publicKey.getEncoded()); } - } catch (GeneralSecurityException | IllegalArgumentException e) { - log.error("[{}] Failed generate Server RPK for profile", e.getMessage()); - throw new RuntimeException(e); } - return null; + } catch (GeneralSecurityException | IllegalArgumentException e) { + log.error("[{}] Failed generate Server RPK for profile", e.getMessage()); + throw new RuntimeException(e); } + return null; } +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mObject.java b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mObject.java index 5afb37c720..4bd700fdf9 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mObject.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mObject.java @@ -16,11 +16,7 @@ package org.thingsboard.server.common.data.lwm2m; import lombok.Data; -import lombok.Getter; -import lombok.Setter; -@Setter -@Getter @Data public class LwM2mObject { int id; From 1ed44010e4dc957a30a1e37a3c6979dbc7a900f9 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Sat, 23 Jan 2021 11:20:35 +0200 Subject: [PATCH 065/249] Lwm2m: update serverKetStore.jks --- .../resources/credentials/serverKeyStore.jks | Bin 5708 -> 5708 bytes .../main/data/credentials/serverKeyStore.jks | Bin 5708 -> 5708 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/common/transport/lwm2m/src/main/resources/credentials/serverKeyStore.jks b/common/transport/lwm2m/src/main/resources/credentials/serverKeyStore.jks index e1d6deff4b3fd948655f802da4ad65f0ba568f4a..9336dd11684c6cd9b2993149b2144d2d1cb30155 100644 GIT binary patch delta 5401 zcmV+!73S*9EX*vBV`J^SL%qhDFiXf1u5&V+63hvww~7J-0K-rONOXpy$&>qPLKKTO zT2=zf1YP?~0e1|bu$|>}w*z3UV~AI`RHb$9e#NY|HSEZOSUV`~NUy4xH4ESDg+yO< zMugKf@~pwmh>^xQ3^+3}H#9diGB_}S&XGVPW3v|93_4T!@AhNe>Z7(R3JQH`VgdsI z!%zfBG(7$8uD>3}+2kIEaK(?G`QtdlaT>G2{<$X$!-gfd-Ko zJm&MIuW`_yIw>g^P4-yU4AR$;p=|XWEU_8GBQ}l#@KiFk^)Wy&8wLp~hDe6@4FL%h zF%BLK0CNCk0CE6!0F!4g6 zu1dqyBU>neDF!0xii=^iE(yx02@?56k7+7w_w+HNljCK7Zx;n&`V(o~f*G#8O`u*E z#XkIhL`k6}Urk9?OU@MFpFK^h1vXY)(c4RskPwF&%hlkgY#3r0on3xf<)-EyrQjLV z;fK9NpD;@KPI@Go>52h84gKW}+i7C5FlJ3|V1=o3y_OT${bp0KO5aab6d1s%lDmD& z9djOg&+(kmtUDGH(rVtp7qz21PWTP#G|jMolytc`S_qWZ9dl&j=$U?{lW%YTiR2Z| zey|uhvKG zVo*K=&;Vqp$kW=W*1tjj@pAWWA>vARqTDhU;k!#ITql0KyBUuW z1~q8zIaMr61pdrK83A8vosnE^GDvS_458=axxKYx7GFm+kBG8B8sQtB8K7xQCswsrRUX&-Eoz8X+&>#yT@@#jM0ssePS zey~J*eGOdP=VRQCWf&p(Vr`0**M~AzLGy_c3?J;iCOP|oYKbRcMn>@zYIos8x*WtO ztu*%tuhBopB@4S1yCI-_q>tKvpUJMY!f6jn3HxZtM;8ekmi=8y&dbLM86GwH{|*~k zKwStg8I;}Gsi~(=8g^WkzqJ{SC>G`FHje@L!_K`I;vu&%&Ucf9=0PxF{-?)QZe>Gt z2n=O9qS(h)gXU00p)bO3*oCQ~=-Zcp%I64~NVp`++so(k6d1d*oVXc(X>V$;1IQb% z!rD#mY;RrwZ0iaQd&s3W)+kx7wXssdeHtEUI})lVkZCc^&)^Yzc0>*zbUTMYS*tMP z+Li{N_P1_m8aglR#!obu_Y`I}7>kYRrL@Z`b2qFa>6GD#sU1W?R?{JA2#2X(M!!JEDgSa$Az)HMeYRbf+&{u2;;?vHX(!W0e$6u^ddHqdKladnJGMQOeP zjfJ0#lO|m6)bz9`D}3Y0U@sK~|AwHtfG>``{Y#@_;qSh?ww|rQrm1MHBd?1De?@WM$@)7|o71GxfriczzjidaT&{Uy6dl+$qEe!R$XB z1$vx)YL0yOk=CVvWJJtu{&&a8p0SwzVNOi^N@jSX2d<9l3i8A za4E8*Q|^T<=qQ+I4pOA{gM&2;q&W$LK?Vbg!CZ{vR3o+DSnGE+cA)w($4Lkxb%_+M7vdYuIs!=yR5Z93Pg=*1+|D%|M`5Ty!p8?K!vpvd;m& zB%j3>hoq#-pD|VcJib0>>?Wa=G;($ME?>|4k;$G`leE1^SFT!0`#4S~1iQp7ljt51>6lFko#fz_;kAm7FwjgVyky$KM$=&)Js0>}Z{ zN%pVA?7gac-xC$I|i!rC>vl*^eeyR;G8tYPt$XVYNwLRgVL1drC) zI_L<0_rOo3!=9(`SGiXU=SH3l@k8CA8abiS#L79GAZ`v9J#}9WjkD|1iCxcdk~9@~ zdM8ITKn{nDw)JzkRTlU$67g!h5t<#AujvUbZCUoj>Yw{ErLe9Xv190UmT0#lUICvW2 z7vna_cFbKMJUwVj+5NWdv?EON_c^g3OEFCl_EEEsBBMC==t}t&EY;i5&+D5x_HF+6 z(Xnmt9|m{i2QC`pW!#WaKR3Tu3y-qfo70Mdu5-urzydoZtLABGYRMN^2@$V<&gY!R zb@l;$d-)p4CKP_G`Rb}}vZ7R8;W})S;(81cJuuc3)zZvgn$YxGSLgp&pg?jg4z_2# zub3#hItE+4IBHAESKHPRI;VQCG816Ao$Oay;R4j9H_I3vpoHO4E#Vw?D5BnvxTg(f zO(oFYJ*N~z)O^Hqvu3fJLuA2!RW!_lFeYZp59owQC&2JmDJvezoNNspeh!O{CZl|c zi-E@+YjZHaRkZ5@UVD-J!29D-;3VgNzx}dSk91t@tRi78oD9~6@(BDRpUi^VI-t$K zX&LHbDm}zLNSLt7^lVCXD9?i-_jGV-83vbJI&${W|3#1+l+hY%wQweX#f!|&3eRFy z{`#_^3l99vVv=#u0(s98fz}z!vaX(6N64NSR8BW{?n)=Y=0JQu((x6`1!hoe$`Un1 zEA|R;_Bp$vUhp(Kc2}YgqYrgH2@`RDm=AA&8w{0ofD98qnbdF_p9Qnx`EsXe-Lu+v z&Kw-y8~Ev(z~on5Vg0SFKFpZ#jTvg0eFE- zrMYW^*Ny_`>r;e>&b8$x-{p~6pSVZbxA;QZlwY9_Ok(LqlPGY-vllW{jSfVwnKy(o zPv;s8YwYL43CxJ2N~tidiP@`e>_@g)+GvV#3_sfN1atv*wH^vAty72 zxb16<3up;5?#U!bNKx}Tg;`hm47rRG-dKdnCfR6;8362R+G>%2@h1&nN|r8drV!tM zlqsoVRe!5=0%J8m9BZ(Ifel7YVl{!jHuYQsB>^ks-l&In04S1IX zz13ZgLce-|e6vMDw{@<7M_;IOs}EfNqq3DE&*{A^;s>dJ)d{B5+vY)o>OI`RRLGNR zgj%T;-$$g|ywQ!9WRuI;$Jb%e8y%5YV44Ag1${K%GqjV-Od)cswj5oC%C#1=L*wQm zAj}&H&xtXQ09hE|h@R`dR-Xz@%N4W`gK(AOdvU9dq&i|naz+N#Ux;l&PCl}lXBIh? z^(R31%C%#EFqgi{A@FRq#KJe+Jc5Sy1e@d$d+^NgKkxVQ`?KKvGNv`nyB8+SI03f- z@A-quy*5KHtW|t}$jB6%T}H4zG;zEw>>|WO)Rr|8DqN8GeWc=;~!}s!{wn0>tE2eA(%43l92m8O zo8TYGFo&=2kS2!M!aWWy9LF@tCfH%D8MbKhK#2A%=6l{QXC>u!~Na%d>*&OC2LaWqPt0atky&#i)4`{cBqSCn!qY-oCim zHbm_h#rNR`h7Kwha|VY0n#lCXAE})AH<`sVm~|ITju-5ON6VK16#CHG|JMH-7gvh0 z^%BvC#UPF7S@;zpiX5iG`c-0{IUy%-g?o|S-L;ONa{x&vk5E4J1H zDLdasQk0?hBz9DfFAl*gByD9wH#VcaW;I)r)?cAvc>4v}E7-|KP(1{r#}x_t+UE*? zo>l&;*Rt`L1c6sU4>ef{UK!e9$8K_kj%2&0^>;^|92Aq2xn6aTwG7Y@^>Gh z!}8bX?)q>d(ZiA)Hpw=i1U6LuYaVe*P%7YyL`Y^g;|3*DG2kI8>JATYo8KbheGuFg zUombMQgbnF-6k1PQmca^hE(~_Zf;zE=jXM-w}I-ii^<>P&l4iF=`SkeVLo=PreIP} zp;O;&VGB6twU`_`vEfMP$lFwau$L|NG~u(M(L3W}`Up-x{BS9(6a+xJdf)X?$9AuE z^X(gl;OpvrnAR1Kt2BZQh*m<;>ir2$Tc@NWKfiTQErRLK)nU8R)mBL&4k>JZ4Lzr* zrhl7Qr+I#AyDeekf<7MnCgwO*_3QvBzIH#jhbzwrJkc9EIeU{?@uK;s1eo{Kq(hDa80z1c&emfin(DQNZi(y^W83a^7AJ26> z^hY(Pm5~|`KAvshLbNd)`O&q1r!X=>!axgDbv$sieOZRUST&()F#(5=4~0Q0{mt=@ zteaYbls&yZMtlukchKH!NL;u0i1>e?@c|@fz;*2#)9{B8uS)cnw*vCJR+10|Ghj1_?YWI{~ zB$D)vRBCDxR7W6Bggxm*CADiFc%%yKRwDP%<%5U>D{g4@j|W|?lvZ)eV#AnDMjs>j zYwrH`p&?25iCfw~u|Ok#{>=A@&%ZJfrlv{&I@3gB8XcBR&Iv|`pv)C(R&%TXpn4<6}9fGw1O>bXpk@4cKP@3FUO zufe$S9Z7Y&SRHVtA0f_o7blce6fTqX5m+U@AkHL&AGmYxJBS%C%izUrl#M`XjVRjz zc6qfNNF+7GWsW6(L{tzVGyFdcv8hh3$={Lj*3+NfewK%AQ^=W@HSV)jQ9h@(D(uI? z2@Tp6wlIfRmY6**NYh^b-ZX%`U8^h+=*+m$l~RXQW4qQ-hSVD0MXdmEdG|RM1@@E# zOBkzArRtI0ltTAqtom#rkb31wC*|tf0x7NF*H{n+`GN+2Q;Q0&!0VfYiq^n_U72{v ze?f=bf=5OoSQ3#RAc+3IalMg%Q0yewtvwmG@;tp6<9D3ElP~-@Wg_lp)xhw53xn%d zVk;#m@mpf72L-4~iEZi;u=`H{OJRPl6Ysu~JmO}>p#mq9$ezx!B!J;`wJ+0tIA);- zz3)k}Zv<4+t2f^)9h$4J}@CL2?hl#4g&%j z1povTM)BJ@{l0oWI{;gv*}H|XVlr4d1Qet3-^6VcvSQ{&3~73V6_0W`$PG6F0|ADh D0a;A9 delta 5401 zcmV+!73S*9EX*vBV`F^A$JgSfjw=w@^p~;BU{`=raLED#0K-rONSy9I@6U;BHkJ*> z_uD%3KZW3*U6CBO{3{WAk62B z!%zfB?PDq<`<~4qd+l%${3I)^5^;DzGvT_%?vt+ImzPQI1ST4WnqrA<$wa|;JIaI2 z3@*sl!woY>(59HZCVHc5)G;`SFqKcOlaT>G2{ko0FflPRF))!mCV%)$3DB8U9LglI zgHnvWnHl|YMco1e0K-rONJDN?1NA?hvp(P_ceP)X?e7`K3{;r*pWK_woOE>q6Jkzq z-M0*ILa3~X+FDO=9+tks70nZ?RIH$1y-K8wLp~hDe6@4FL%h zF%BLK0CNCk0CE6!0F!8|~!`Xp;(Fb!W$y-}JizivrMsottSq`{zptU+I=dk4V~ zxgz6#U5qn9S~ITLla19H+r9J6TwdwLxMr)Wu(sSfTAcWCL8_ShiobmZD5eYlS{~6{ zM@YaEo>nCAOVA2cnrkb76|BROcF5^Ev9)OE+K&4Cg(o1ePVlR<2-3XN7(DAr(Rk4G zpAWK2R)WIEf>)eF!@HYbY{n$cLzN38!DA_ZoNE58YdM&U+G@J11>#J`x#I8UPq_w5 z*`VjAA;Vg@8v2pm$cRk*VN-sm z6n3Wh!(#b%%s^_CR4RF{d2If6BUHVL8C}aKsp0Evx>sMds;y-YM5eYD4Jom zxJ)^aRg{3o*;ag3F?$g|k3IR;9mj_n2KIz5kHY)V_=Zu->b{d~VAIK_#B0ZY(NL#s zj~61LOq8Tse-7UMHrJ7emzg}SWzQb)t<2rI>AhvtYeXWMJaW(7caBl_tl)&5KPI%2 zcaB?IN;))k&JBK^yn_30*~#2hY{aEwP{q5yfV95o z;w*Hlq;*E!8&|9Q<&X5|*`JI~|179aIWuNW{kh8GZkTrZ>&3+y1jk^1tb4nnEG=D4 zS9-Q&OK;eI=z{6~EL|TwQiE{|1#|PA#KE?e+cR8;C^T$iSHKm&Ot5|7VR(wHf4d_I z&Koig6emb&L^$DFk$2^jERL?M%01aNq2{DRtr9+-;#9Bnw(E3U0=$CZn6y`=iqx|n zk7u4!%qq;-SGnk=_K#kFcj+d`53Ui+-miI)ifni0o2FQZ&uB~gQ$xj<;ShAo|RM#rAeL>z5!MaQ(;e|uYrMUR?b)*SN z(i`o;*m2dTTx097s(pg*!a%Xfd}hUKS#yd|0qG!e>S~L{5+k(8rzFjw1pT$@l?CYJ zsi*;adeGwDggF@Kqm?EEqrp1tsEQH{uQA{DKTUSY$Y*W1uDL&8EQ|G(XN0oz@14jc ziW6=T_66~Oj*f9aw2U3^a76PHj8@cyU!tnM17+{G{opz67JPfUmb}d2*IYadg|eM} zD}5-90&9ZWnBBIT#pw^o$0_^jvsanQ`4kXmR0ab=Y$Sw(HBmFuVSz$cnM&Vkx(VWk zV~zWkm~gW>@((00)UC>iDDZ1s)G)O4ThlS}P)7KF9E+foO(tBc>j_+lb>Uibe_z^V zNCdnWCDi>;Ld_f#VZIAF&QR5)JHb@R4tN1DjoWxFjakFU7ZD1W@O16`t(?D{5O(<^ zuqQ;uFY@!1e$u{Y8?ywJ(vwVGeQ4$f=)ToJP!UPn0xRe($$ngjgVcCYY8Gdl47}_o zHEeW$CSupk!$ycwv|W1Y`7POAjN6$!M>KL8Qr_$%GKwOhd#&m8Rr-q2Y9u2cxZj7TI`RFpElf`fC7uIxTY`YcBjX5VELF za&(sMhMROvKpx~1APkUNKsoe)Yl&E1pBnbP_zv6{vDVPj8tQ3W&v;hT8(bmPEOQ%U z{K}7FEc0qSIy4cZc$PMXau9hC1CztsCfK8(0dpP#?BRaOGiCsq7)f zmX-XMn(WxFq9X}GS7GypW-(Flflep--)h|p$%FKKm6#EnAV4!8HoLNX?rUFSWj$ic z`I`YC7)leSgA>gT2*v^pTh-PWgGRqFDE#G1|XdEO{|4UwvxjVjpHc|^Q zRAXaTQz3IL)Cqw9Qy&!yWY{WGX>LSg5ouCpeX zayt7c?OIL$DI8};(}LjStz(;ie>I~HY`N;i@iJOr77~}(^sSV39*S7G3ns=nJ_}^Q ztE@a##M-7mH&}gJ8VU^FF;r<52~XC4Bb>u>(Er&o^sZ_{Y{9F-z5t25Vn&)6qeQx~ zY{nITqxBPe{XH$@F`stO$#N%;f+kaTWf!BaC=P|!*tk~RqfQ$$XaHV+)nU8gOfn>M zw`!qNl$8=VLxj7CSgwa&djRykPwQE&5CH&|^A0ak2vxgbr!i(f)4Jm3NJe%r^vsn9 zzk{@-3zw%??&HuDsWcd5FzSQ0X`^qIjw4){_V?Azb|NWB?H0)(&qPs61=o_XDHzrl z=ZL<;ZUW{7){WB}eV9alQcafxjJBR{6tJW}3GC2OP%@)L!Lc(|+&P2c7vdpQGCb=Q24B-TS0Pe-iHScIHb2Uv# zLmci+$c)_R&8Bm`xx&l7MRkgDf~4>^BD0(n-z!`YBnCQ)Z>fKCL|Y6@OUi*9&qP}l z9)Jfepfuz@(B;*vSchol-*1$`^Edd_i2<2Zq}FV^dGMv9(HZH;Ksyoc8fEqv?Fm;( zk$$}UN9o#(-FSn48q(|+rIXqv5P-Mg?WY94qs6(fw^SwvwzHt}Y>Mtb86zPb^kn<* z{YvN#^enc5gV}KFuCK(?`b`Pj_~3osrI(~W#R)it!s1diQ1bR*wyI%pI>iXYw5%WR zfuae=f3k;Z^MpJT zXy{xh)yP5=q0D(8D$68xY-g|t}h_uYuQqT-79_4u_NvWhbhCjBazRj1dA_n7i8 z{*oT^LE_PWvH?hJGKdl5c3ug-<$&0Kw-Fhbt#Qnuj$x7~=AUg%!(~M_FS){+ z+nZnCN^s$1hscR5jI)M#Zuj>ovDoYTmN@A+9RVl1a#u-CX!zH4uQovQV@Qi8DM*>FM)Tc@F??t6friS#GOOq!K+15jZG$Q$GTjlr^fT_ zD4~beZ-#<8cV)lhp^^4rca`M{VQFok57PNn?Ku3_Z_Amg1Ys-iZMkE%x0|R@L7N!B z+FgmacRtK%{0|!6q26Eh;g4I5v)r5oxVyV58uSdX8J$`G^|{?>HRnN(=-C(? z!Vt&7T`~T$-cOjYMZqNW`E3B&k)qUI5(%7d3-@S;82jC=UOvC3AsoPu13VxibQy>3iv<3Mq`Z{=p9slF=c5*$U8m?G~`(vshJI{=XY|Z3~4}Vu;#q3Of4E4)B?sGp> zBIF2>=Si#iPI)=&2SYN4(5A$5ort29iVZ!hZ$kMfygj5~0({ArZb@WZ zAcPY~qOwl#o@KG94_h&<`@DmHsP00vw5%b~i+p~hxfHQDL|k9E1)kLg`R;@llgs{D z&sGO2-i{>9JP|15*Mj+&#HOnbiFn|$$}EltpUC^S(1E(aEAeq?r%&s=S80)Wn$*V( zHJp~Okb!2fJ6d$RnnB91);e!J66EH!WL&ZMVp{*C72@@lf^tF|FR&unsOc=KPa%?j zZpEF`U3dyuL{h|T`rSHGse6M4iH~qk9BzWi5T0lc$VI5JBDJ@1N57N$K!kx5nG@v* zU`6>4sX+c`@y7@Pr(SlXnGO~r_Wm`<0lESUb{))q9)Z34Xh z`5e$n@vaLVq?T3d~{wv9=DNPFiRZ7>_PntJqwGMpJiox((TU0LvpHLT+Gs(776@xo-%v&r0m zhUR?}Bfy!zbKk!p5Wa_6<)LzAQ?Yrvj+qLFej)N1cL~Xv)^210YctqsH{=8n$1jJu zA<-p);b=TAf8_aYY?E9m24Uz7qWr!v6<)%LJ+Ei!VGL7$dC-@shGhKnLDOr~pVRhY zS8TniCW+uh4&!flt6L{cJPP&cr6(JJuQ>^=XHS1g@GL2x+nuIzcS1&VFzqe=Zy&$> zdp6xCx-{!(a2+JR3n=6KvE|qkhOgvX^nFFm=Kns!L6;^4`$;bd+=7aKoJxW7<$@Ia zJuNOnTjzX#LT5PDBAIjz4AM7x^t?bb{&>{ARA2D!hUUkf_R!rqPLKKTO zT2=zf1YP?~0e1|bu$|>}w*z3UV~AI`RHb$9e#NY|HSEZOSUV`~NUy4xH4ESDg+yO< zMugKf@~pwmh>^xQ3^+3}H#9diGB_}S&XGVPW3v|93_4T!@AhNe>Z7(R3JQH`VgdsI z!%zfBG(7$8uD>3}+2kIEaK(?G`QtdlaT>G2{<$X$!-gfd-Ko zJm&MIuW`_yIw>g^P4-yU4AR$;p=|XWEU_8GBQ}l#@KiFk^)Wy&8wLp~hDe6@4FL%h zF%BLK0CNCk0CE6!0F!4g6 zu1dqyBU>neDF!0xii=^iE(yx02@?56k7+7w_w+HNljCK7Zx;n&`V(o~f*G#8O`u*E z#XkIhL`k6}Urk9?OU@MFpFK^h1vXY)(c4RskPwF&%hlkgY#3r0on3xf<)-EyrQjLV z;fK9NpD;@KPI@Go>52h84gKW}+i7C5FlJ3|V1=o3y_OT${bp0KO5aab6d1s%lDmD& z9djOg&+(kmtUDGH(rVtp7qz21PWTP#G|jMolytc`S_qWZ9dl&j=$U?{lW%YTiR2Z| zey|uhvKG zVo*K=&;Vqp$kW=W*1tjj@pAWWA>vARqTDhU;k!#ITql0KyBUuW z1~q8zIaMr61pdrK83A8vosnE^GDvS_458=axxKYx7GFm+kBG8B8sQtB8K7xQCswsrRUX&-Eoz8X+&>#yT@@#jM0ssePS zey~J*eGOdP=VRQCWf&p(Vr`0**M~AzLGy_c3?J;iCOP|oYKbRcMn>@zYIos8x*WtO ztu*%tuhBopB@4S1yCI-_q>tKvpUJMY!f6jn3HxZtM;8ekmi=8y&dbLM86GwH{|*~k zKwStg8I;}Gsi~(=8g^WkzqJ{SC>G`FHje@L!_K`I;vu&%&Ucf9=0PxF{-?)QZe>Gt z2n=O9qS(h)gXU00p)bO3*oCQ~=-Zcp%I64~NVp`++so(k6d1d*oVXc(X>V$;1IQb% z!rD#mY;RrwZ0iaQd&s3W)+kx7wXssdeHtEUI})lVkZCc^&)^Yzc0>*zbUTMYS*tMP z+Li{N_P1_m8aglR#!obu_Y`I}7>kYRrL@Z`b2qFa>6GD#sU1W?R?{JA2#2X(M!!JEDgSa$Az)HMeYRbf+&{u2;;?vHX(!W0e$6u^ddHqdKladnJGMQOeP zjfJ0#lO|m6)bz9`D}3Y0U@sK~|AwHtfG>``{Y#@_;qSh?ww|rQrm1MHBd?1De?@WM$@)7|o71GxfriczzjidaT&{Uy6dl+$qEe!R$XB z1$vx)YL0yOk=CVvWJJtu{&&a8p0SwzVNOi^N@jSX2d<9l3i8A za4E8*Q|^T<=qQ+I4pOA{gM&2;q&W$LK?Vbg!CZ{vR3o+DSnGE+cA)w($4Lkxb%_+M7vdYuIs!=yR5Z93Pg=*1+|D%|M`5Ty!p8?K!vpvd;m& zB%j3>hoq#-pD|VcJib0>>?Wa=G;($ME?>|4k;$G`leE1^SFT!0`#4S~1iQp7ljt51>6lFko#fz_;kAm7FwjgVyky$KM$=&)Js0>}Z{ zN%pVA?7gac-xC$I|i!rC>vl*^eeyR;G8tYPt$XVYNwLRgVL1drC) zI_L<0_rOo3!=9(`SGiXU=SH3l@k8CA8abiS#L79GAZ`v9J#}9WjkD|1iCxcdk~9@~ zdM8ITKn{nDw)JzkRTlU$67g!h5t<#AujvUbZCUoj>Yw{ErLe9Xv190UmT0#lUICvW2 z7vna_cFbKMJUwVj+5NWdv?EON_c^g3OEFCl_EEEsBBMC==t}t&EY;i5&+D5x_HF+6 z(Xnmt9|m{i2QC`pW!#WaKR3Tu3y-qfo70Mdu5-urzydoZtLABGYRMN^2@$V<&gY!R zb@l;$d-)p4CKP_G`Rb}}vZ7R8;W})S;(81cJuuc3)zZvgn$YxGSLgp&pg?jg4z_2# zub3#hItE+4IBHAESKHPRI;VQCG816Ao$Oay;R4j9H_I3vpoHO4E#Vw?D5BnvxTg(f zO(oFYJ*N~z)O^Hqvu3fJLuA2!RW!_lFeYZp59owQC&2JmDJvezoNNspeh!O{CZl|c zi-E@+YjZHaRkZ5@UVD-J!29D-;3VgNzx}dSk91t@tRi78oD9~6@(BDRpUi^VI-t$K zX&LHbDm}zLNSLt7^lVCXD9?i-_jGV-83vbJI&${W|3#1+l+hY%wQweX#f!|&3eRFy z{`#_^3l99vVv=#u0(s98fz}z!vaX(6N64NSR8BW{?n)=Y=0JQu((x6`1!hoe$`Un1 zEA|R;_Bp$vUhp(Kc2}YgqYrgH2@`RDm=AA&8w{0ofD98qnbdF_p9Qnx`EsXe-Lu+v z&Kw-y8~Ev(z~on5Vg0SFKFpZ#jTvg0eFE- zrMYW^*Ny_`>r;e>&b8$x-{p~6pSVZbxA;QZlwY9_Ok(LqlPGY-vllW{jSfVwnKy(o zPv;s8YwYL43CxJ2N~tidiP@`e>_@g)+GvV#3_sfN1atv*wH^vAty72 zxb16<3up;5?#U!bNKx}Tg;`hm47rRG-dKdnCfR6;8362R+G>%2@h1&nN|r8drV!tM zlqsoVRe!5=0%J8m9BZ(Ifel7YVl{!jHuYQsB>^ks-l&In04S1IX zz13ZgLce-|e6vMDw{@<7M_;IOs}EfNqq3DE&*{A^;s>dJ)d{B5+vY)o>OI`RRLGNR zgj%T;-$$g|ywQ!9WRuI;$Jb%e8y%5YV44Ag1${K%GqjV-Od)cswj5oC%C#1=L*wQm zAj}&H&xtXQ09hE|h@R`dR-Xz@%N4W`gK(AOdvU9dq&i|naz+N#Ux;l&PCl}lXBIh? z^(R31%C%#EFqgi{A@FRq#KJe+Jc5Sy1e@d$d+^NgKkxVQ`?KKvGNv`nyB8+SI03f- z@A-quy*5KHtW|t}$jB6%T}H4zG;zEw>>|WO)Rr|8DqN8GeWc=;~!}s!{wn0>tE2eA(%43l92m8O zo8TYGFo&=2kS2!M!aWWy9LF@tCfH%D8MbKhK#2A%=6l{QXC>u!~Na%d>*&OC2LaWqPt0atky&#i)4`{cBqSCn!qY-oCim zHbm_h#rNR`h7Kwha|VY0n#lCXAE})AH<`sVm~|ITju-5ON6VK16#CHG|JMH-7gvh0 z^%BvC#UPF7S@;zpiX5iG`c-0{IUy%-g?o|S-L;ONa{x&vk5E4J1H zDLdasQk0?hBz9DfFAl*gByD9wH#VcaW;I)r)?cAvc>4v}E7-|KP(1{r#}x_t+UE*? zo>l&;*Rt`L1c6sU4>ef{UK!e9$8K_kj%2&0^>;^|92Aq2xn6aTwG7Y@^>Gh z!}8bX?)q>d(ZiA)Hpw=i1U6LuYaVe*P%7YyL`Y^g;|3*DG2kI8>JATYo8KbheGuFg zUombMQgbnF-6k1PQmca^hE(~_Zf;zE=jXM-w}I-ii^<>P&l4iF=`SkeVLo=PreIP} zp;O;&VGB6twU`_`vEfMP$lFwau$L|NG~u(M(L3W}`Up-x{BS9(6a+xJdf)X?$9AuE z^X(gl;OpvrnAR1Kt2BZQh*m<;>ir2$Tc@NWKfiTQErRLK)nU8R)mBL&4k>JZ4Lzr* zrhl7Qr+I#AyDeekf<7MnCgwO*_3QvBzIH#jhbzwrJkc9EIeU{?@uK;s1eo{Kq(hDa80z1c&emfin(DQNZi(y^W83a^7AJ26> z^hY(Pm5~|`KAvshLbNd)`O&q1r!X=>!axgDbv$sieOZRUST&()F#(5=4~0Q0{mt=@ zteaYbls&yZMtlukchKH!NL;u0i1>e?@c|@fz;*2#)9{B8uS)cnw*vCJR+10|Ghj1_?YWI{~ zB$D)vRBCDxR7W6Bggxm*CADiFc%%yKRwDP%<%5U>D{g4@j|W|?lvZ)eV#AnDMjs>j zYwrH`p&?25iCfw~u|Ok#{>=A@&%ZJfrlv{&I@3gB8XcBR&Iv|`pv)C(R&%TXpn4<6}9fGw1O>bXpk@4cKP@3FUO zufe$S9Z7Y&SRHVtA0f_o7blce6fTqX5m+U@AkHL&AGmYxJBS%C%izUrl#M`XjVRjz zc6qfNNF+7GWsW6(L{tzVGyFdcv8hh3$={Lj*3+NfewK%AQ^=W@HSV)jQ9h@(D(uI? z2@Tp6wlIfRmY6**NYh^b-ZX%`U8^h+=*+m$l~RXQW4qQ-hSVD0MXdmEdG|RM1@@E# zOBkzArRtI0ltTAqtom#rkb31wC*|tf0x7NF*H{n+`GN+2Q;Q0&!0VfYiq^n_U72{v ze?f=bf=5OoSQ3#RAc+3IalMg%Q0yewtvwmG@;tp6<9D3ElP~-@Wg_lp)xhw53xn%d zVk;#m@mpf72L-4~iEZi;u=`H{OJRPl6Ysu~JmO}>p#mq9$ezx!B!J;`wJ+0tIA);- zz3)k}Zv<4+t2f^)9h$4J}@CL2?hl#4g&%j z1povTM)BJ@{l0oWI{;gv*}H|XVlr4d1Qet3-^6VcvSQ{&3~73V6_0W`$PG6F0|ADh D0a;A9 delta 5401 zcmV+!73S*9EX*vBV`F^A$JgSfjw=w@^p~;BU{`=raLED#0K-rONSy9I@6U;BHkJ*> z_uD%3KZW3*U6CBO{3{WAk62B z!%zfB?PDq<`<~4qd+l%${3I)^5^;DzGvT_%?vt+ImzPQI1ST4WnqrA<$wa|;JIaI2 z3@*sl!woY>(59HZCVHc5)G;`SFqKcOlaT>G2{ko0FflPRF))!mCV%)$3DB8U9LglI zgHnvWnHl|YMco1e0K-rONJDN?1NA?hvp(P_ceP)X?e7`K3{;r*pWK_woOE>q6Jkzq z-M0*ILa3~X+FDO=9+tks70nZ?RIH$1y-K8wLp~hDe6@4FL%h zF%BLK0CNCk0CE6!0F!8|~!`Xp;(Fb!W$y-}JizivrMsottSq`{zptU+I=dk4V~ zxgz6#U5qn9S~ITLla19H+r9J6TwdwLxMr)Wu(sSfTAcWCL8_ShiobmZD5eYlS{~6{ zM@YaEo>nCAOVA2cnrkb76|BROcF5^Ev9)OE+K&4Cg(o1ePVlR<2-3XN7(DAr(Rk4G zpAWK2R)WIEf>)eF!@HYbY{n$cLzN38!DA_ZoNE58YdM&U+G@J11>#J`x#I8UPq_w5 z*`VjAA;Vg@8v2pm$cRk*VN-sm z6n3Wh!(#b%%s^_CR4RF{d2If6BUHVL8C}aKsp0Evx>sMds;y-YM5eYD4Jom zxJ)^aRg{3o*;ag3F?$g|k3IR;9mj_n2KIz5kHY)V_=Zu->b{d~VAIK_#B0ZY(NL#s zj~61LOq8Tse-7UMHrJ7emzg}SWzQb)t<2rI>AhvtYeXWMJaW(7caBl_tl)&5KPI%2 zcaB?IN;))k&JBK^yn_30*~#2hY{aEwP{q5yfV95o z;w*Hlq;*E!8&|9Q<&X5|*`JI~|179aIWuNW{kh8GZkTrZ>&3+y1jk^1tb4nnEG=D4 zS9-Q&OK;eI=z{6~EL|TwQiE{|1#|PA#KE?e+cR8;C^T$iSHKm&Ot5|7VR(wHf4d_I z&Koig6emb&L^$DFk$2^jERL?M%01aNq2{DRtr9+-;#9Bnw(E3U0=$CZn6y`=iqx|n zk7u4!%qq;-SGnk=_K#kFcj+d`53Ui+-miI)ifni0o2FQZ&uB~gQ$xj<;ShAo|RM#rAeL>z5!MaQ(;e|uYrMUR?b)*SN z(i`o;*m2dTTx097s(pg*!a%Xfd}hUKS#yd|0qG!e>S~L{5+k(8rzFjw1pT$@l?CYJ zsi*;adeGwDggF@Kqm?EEqrp1tsEQH{uQA{DKTUSY$Y*W1uDL&8EQ|G(XN0oz@14jc ziW6=T_66~Oj*f9aw2U3^a76PHj8@cyU!tnM17+{G{opz67JPfUmb}d2*IYadg|eM} zD}5-90&9ZWnBBIT#pw^o$0_^jvsanQ`4kXmR0ab=Y$Sw(HBmFuVSz$cnM&Vkx(VWk zV~zWkm~gW>@((00)UC>iDDZ1s)G)O4ThlS}P)7KF9E+foO(tBc>j_+lb>Uibe_z^V zNCdnWCDi>;Ld_f#VZIAF&QR5)JHb@R4tN1DjoWxFjakFU7ZD1W@O16`t(?D{5O(<^ zuqQ;uFY@!1e$u{Y8?ywJ(vwVGeQ4$f=)ToJP!UPn0xRe($$ngjgVcCYY8Gdl47}_o zHEeW$CSupk!$ycwv|W1Y`7POAjN6$!M>KL8Qr_$%GKwOhd#&m8Rr-q2Y9u2cxZj7TI`RFpElf`fC7uIxTY`YcBjX5VELF za&(sMhMROvKpx~1APkUNKsoe)Yl&E1pBnbP_zv6{vDVPj8tQ3W&v;hT8(bmPEOQ%U z{K}7FEc0qSIy4cZc$PMXau9hC1CztsCfK8(0dpP#?BRaOGiCsq7)f zmX-XMn(WxFq9X}GS7GypW-(Flflep--)h|p$%FKKm6#EnAV4!8HoLNX?rUFSWj$ic z`I`YC7)leSgA>gT2*v^pTh-PWgGRqFDE#G1|XdEO{|4UwvxjVjpHc|^Q zRAXaTQz3IL)Cqw9Qy&!yWY{WGX>LSg5ouCpeX zayt7c?OIL$DI8};(}LjStz(;ie>I~HY`N;i@iJOr77~}(^sSV39*S7G3ns=nJ_}^Q ztE@a##M-7mH&}gJ8VU^FF;r<52~XC4Bb>u>(Er&o^sZ_{Y{9F-z5t25Vn&)6qeQx~ zY{nITqxBPe{XH$@F`stO$#N%;f+kaTWf!BaC=P|!*tk~RqfQ$$XaHV+)nU8gOfn>M zw`!qNl$8=VLxj7CSgwa&djRykPwQE&5CH&|^A0ak2vxgbr!i(f)4Jm3NJe%r^vsn9 zzk{@-3zw%??&HuDsWcd5FzSQ0X`^qIjw4){_V?Azb|NWB?H0)(&qPs61=o_XDHzrl z=ZL<;ZUW{7){WB}eV9alQcafxjJBR{6tJW}3GC2OP%@)L!Lc(|+&P2c7vdpQGCb=Q24B-TS0Pe-iHScIHb2Uv# zLmci+$c)_R&8Bm`xx&l7MRkgDf~4>^BD0(n-z!`YBnCQ)Z>fKCL|Y6@OUi*9&qP}l z9)Jfepfuz@(B;*vSchol-*1$`^Edd_i2<2Zq}FV^dGMv9(HZH;Ksyoc8fEqv?Fm;( zk$$}UN9o#(-FSn48q(|+rIXqv5P-Mg?WY94qs6(fw^SwvwzHt}Y>Mtb86zPb^kn<* z{YvN#^enc5gV}KFuCK(?`b`Pj_~3osrI(~W#R)it!s1diQ1bR*wyI%pI>iXYw5%WR zfuae=f3k;Z^MpJT zXy{xh)yP5=q0D(8D$68xY-g|t}h_uYuQqT-79_4u_NvWhbhCjBazRj1dA_n7i8 z{*oT^LE_PWvH?hJGKdl5c3ug-<$&0Kw-Fhbt#Qnuj$x7~=AUg%!(~M_FS){+ z+nZnCN^s$1hscR5jI)M#Zuj>ovDoYTmN@A+9RVl1a#u-CX!zH4uQovQV@Qi8DM*>FM)Tc@F??t6friS#GOOq!K+15jZG$Q$GTjlr^fT_ zD4~beZ-#<8cV)lhp^^4rca`M{VQFok57PNn?Ku3_Z_Amg1Ys-iZMkE%x0|R@L7N!B z+FgmacRtK%{0|!6q26Eh;g4I5v)r5oxVyV58uSdX8J$`G^|{?>HRnN(=-C(? z!Vt&7T`~T$-cOjYMZqNW`E3B&k)qUI5(%7d3-@S;82jC=UOvC3AsoPu13VxibQy>3iv<3Mq`Z{=p9slF=c5*$U8m?G~`(vshJI{=XY|Z3~4}Vu;#q3Of4E4)B?sGp> zBIF2>=Si#iPI)=&2SYN4(5A$5ort29iVZ!hZ$kMfygj5~0({ArZb@WZ zAcPY~qOwl#o@KG94_h&<`@DmHsP00vw5%b~i+p~hxfHQDL|k9E1)kLg`R;@llgs{D z&sGO2-i{>9JP|15*Mj+&#HOnbiFn|$$}EltpUC^S(1E(aEAeq?r%&s=S80)Wn$*V( zHJp~Okb!2fJ6d$RnnB91);e!J66EH!WL&ZMVp{*C72@@lf^tF|FR&unsOc=KPa%?j zZpEF`U3dyuL{h|T`rSHGse6M4iH~qk9BzWi5T0lc$VI5JBDJ@1N57N$K!kx5nG@v* zU`6>4sX+c`@y7@Pr(SlXnGO~r_Wm`<0lESUb{))q9)Z34Xh z`5e$n@vaLVq?T3d~{wv9=DNPFiRZ7>_PntJqwGMpJiox((TU0LvpHLT+Gs(776@xo-%v&r0m zhUR?}Bfy!zbKk!p5Wa_6<)LzAQ?Yrvj+qLFej)N1cL~Xv)^210YctqsH{=8n$1jJu zA<-p);b=TAf8_aYY?E9m24Uz7qWr!v6<)%LJ+Ei!VGL7$dC-@shGhKnLDOr~pVRhY zS8TniCW+uh4&!flt6L{cJPP&cr6(JJuQ>^=XHS1g@GL2x+nuIzcS1&VFzqe=Zy&$> zdp6xCx-{!(a2+JR3n=6KvE|qkhOgvX^nFFm=Kns!L6;^4`$;bd+=7aKoJxW7<$@Ia zJuNOnTjzX#LT5PDBAIjz4AM7x^t?bb{&>{ARA2D!hUUkf_R!r Date: Mon, 25 Jan 2021 13:01:13 +0200 Subject: [PATCH 066/249] Device wizard: Rollback(delete) device when failed to save device credentials. --- .../wizard/device-wizard-dialog.component.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts index 593d32e2ff..1cba31aa24 100644 --- a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts @@ -39,8 +39,8 @@ import { BaseData, HasId } from '@shared/models/base-data'; import { EntityType } from '@shared/models/entity-type.models'; import { DeviceProfileService } from '@core/http/device-profile.service'; import { EntityId } from '@shared/models/id/entity-id'; -import { Observable, of, Subscription } from 'rxjs'; -import { map, mergeMap, tap } from 'rxjs/operators'; +import { Observable, of, Subscription, throwError } from 'rxjs'; +import { catchError, map, mergeMap, tap } from 'rxjs/operators'; import { DeviceService } from '@core/http/device.service'; import { ErrorStateMatcher } from '@angular/material/core'; import { StepperSelectionEvent } from '@angular/cdk/stepper'; @@ -335,7 +335,15 @@ export class DeviceWizardDialogComponent extends mergeMap( (deviceCredentials) => { const deviceCredentialsValue = {...deviceCredentials, ...this.credentialsFormGroup.value.credential}; - return this.deviceService.saveDeviceCredentials(deviceCredentialsValue); + return this.deviceService.saveDeviceCredentials(deviceCredentialsValue).pipe( + catchError(e => { + return this.deviceService.deleteDevice(device.id.id).pipe( + mergeMap(() => { + return throwError(e); + } + )); + }) + ); } ), map(() => true)); From 4d4d189816005eb84127972ec91a261f8daaae1d Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Mon, 25 Jan 2021 11:32:15 +0200 Subject: [PATCH 067/249] getPropagationEntityIds improvements --- .../org/thingsboard/server/dao/alarm/BaseAlarmService.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java index 808b6b5325..45478ce146 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java @@ -393,7 +393,9 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ private Set getPropagationEntityIds(Alarm alarm) { if (alarm.isPropagate()) { List relations = relationService.findByTo(alarm.getTenantId(), alarm.getId(), RelationTypeGroup.ALARM); - return relations.stream().map(EntityRelation::getFrom).collect(Collectors.toSet()); + Set propagationEntityIds = relations.stream().map(EntityRelation::getFrom).collect(Collectors.toSet()); + propagationEntityIds.add(alarm.getOriginator()); + return propagationEntityIds; } else { return Collections.singleton(alarm.getOriginator()); } From a8e093910a27e0c2ef6314e521d4a8c942e5daa0 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Mon, 25 Jan 2021 15:57:09 +0200 Subject: [PATCH 068/249] Lwm2m: back&front: update filter for objectIds --- .../controller/DeviceLwm2mController.java | 17 +++++++++-------- .../service/lwm2m/LwM2MModelsRepository.java | 17 ++++++++++++----- .../src/app/core/http/device-profile.service.ts | 14 +++++++------- ...profile-transport-configuration.component.ts | 15 ++++++++------- .../device/lwm2m/lwm2m-object-list.component.ts | 16 +++++++--------- 5 files changed, 43 insertions(+), 36 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceLwm2mController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceLwm2mController.java index a12bfb8900..4ddeff5af6 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceLwm2mController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceLwm2mController.java @@ -49,14 +49,15 @@ import java.util.Map; public class DeviceLwm2mController extends BaseController { @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") - @RequestMapping(value = "/lwm2m/deviceProfile", params = {"objectIds"}, method = RequestMethod.GET) + @RequestMapping(value = "/lwm2m/deviceProfile", params = {"sortOrder", "sortProperty"}, method = RequestMethod.GET) @ResponseBody - public List getLwm2mListObjects(@RequestParam int[] objectIds, - @RequestParam(required = false) String textSearch, - @RequestParam(required = false) String sortProperty, - @RequestParam(required = false) String sortOrder) throws ThingsboardException { + public List getLwm2mListObjects(@RequestParam String sortOrder, + @RequestParam String sortProperty, + @RequestParam(required = false) int[] objectIds, + @RequestParam(required = false) String searchText) + throws ThingsboardException { try { - return lwM2MModelsRepository.getLwm2mObjects(objectIds, textSearch, sortProperty, sortOrder); + return lwM2MModelsRepository.getLwm2mObjects(objectIds, searchText, sortProperty, sortOrder); } catch (Exception e) { throw handleException(e); } @@ -67,11 +68,11 @@ public class DeviceLwm2mController extends BaseController { @ResponseBody public PageData getLwm2mListObjects(@RequestParam int pageSize, @RequestParam int page, - @RequestParam(required = false) String textSearch, + @RequestParam(required = false) String searchText, @RequestParam(required = false) String sortProperty, @RequestParam(required = false) String sortOrder) throws ThingsboardException { try { - PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); + PageLink pageLink = createPageLink(pageSize, page, searchText, sortProperty, sortOrder); return checkNotNull(lwM2MModelsRepository.findDeviceLwm2mObjects(getTenantId(), pageLink)); } catch (Exception e) { throw handleException(e); diff --git a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MModelsRepository.java b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MModelsRepository.java index 1eb454c23a..e909dd8741 100644 --- a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MModelsRepository.java +++ b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MModelsRepository.java @@ -81,10 +81,14 @@ public class LwM2MModelsRepository { * if textSearch is null then it uses AllList from List) */ public List getLwm2mObjects(int[] objectIds, String textSearch, String sortProperty, String sortOrder) { - return getLwm2mObjects((objectIds.length > 0 && textSearch != null && !textSearch.isEmpty()) ? - (ObjectModel element) -> IntStream.of(objectIds).anyMatch(x -> x == element.id) || element.name.contains(textSearch) : - (objectIds.length > 0) ? - (ObjectModel element) -> IntStream.of(objectIds).anyMatch(x -> x == element.id) : + if (objectIds == null && textSearch != null && !textSearch.isEmpty()) { + objectIds = getObjectIdFromTextSearch(textSearch); + } + int[] finalObjectIds = objectIds; + return getLwm2mObjects((objectIds != null && objectIds.length > 0 && textSearch != null && !textSearch.isEmpty()) ? + (ObjectModel element) -> IntStream.of(finalObjectIds).anyMatch(x -> x == element.id) || element.name.toLowerCase().contains(textSearch.toLowerCase()) : + (objectIds != null && objectIds.length > 0) ? + (ObjectModel element) -> IntStream.of(finalObjectIds).anyMatch(x -> x == element.id) : (textSearch != null && !textSearch.isEmpty()) ? (ObjectModel element) -> element.name.contains(textSearch) : null, @@ -165,7 +169,10 @@ public class LwM2MModelsRepository { * PageNumber = 1, PageSize = List.size() */ public PageData findLwm2mListObjects(PageLink pageLink) { - PageImpl page = new PageImpl(getLwm2mObjects(getObjectIdFromTextSearch(pageLink.getTextSearch()), pageLink.getTextSearch(), pageLink.getSortOrder().getProperty(), pageLink.getSortOrder().getDirection().name())); + PageImpl page = new PageImpl(getLwm2mObjects(getObjectIdFromTextSearch(pageLink.getTextSearch()), + pageLink.getTextSearch(), + pageLink.getSortOrder().getProperty(), + pageLink.getSortOrder().getDirection().name())); PageData pageData = new PageData(page.getContent(), page.getTotalPages(), page.getTotalElements(), page.hasNext()); return pageData; } diff --git a/ui-ngx/src/app/core/http/device-profile.service.ts b/ui-ngx/src/app/core/http/device-profile.service.ts index df68af629e..26c642c4bc 100644 --- a/ui-ngx/src/app/core/http/device-profile.service.ts +++ b/ui-ngx/src/app/core/http/device-profile.service.ts @@ -21,7 +21,7 @@ import { defaultHttpOptionsFromConfig, RequestConfig } from './http-utils'; import { Observable } from 'rxjs'; import { PageData } from '@shared/models/page/page-data'; import { DeviceProfile, DeviceProfileInfo, DeviceTransportType } from '@shared/models/device.models'; -import { isDefinedAndNotNull } from '@core/utils'; +import { isDefinedAndNotNull, isEmptyStr } from '@core/utils'; import { ObjectLwM2M, ServerSecurityConfig } from '@home/components/profile/device/lwm2m/profile-config.models'; import { SortOrder } from '@shared/models/page/sort-order'; @@ -43,14 +43,14 @@ export class DeviceProfileService { return this.http.get(`/api/deviceProfile/${deviceProfileId}`, defaultHttpOptionsFromConfig(config)); } - public getLwm2mObjects(objectIds: number[] = [], searchText?: string, sortOrder?: SortOrder, config?: RequestConfig): + public getLwm2mObjects(sortOrder: SortOrder, objectIds?: number[], searchText?: string, config?: RequestConfig): Observable> { - let url = `/api/lwm2m/deviceProfile/?objectIds=${objectIds}`; - if (isDefinedAndNotNull(searchText)) { - url += `&searchText=${searchText}`; + let url = `/api/lwm2m/deviceProfile/?sortProperty=${sortOrder.property}&sortOrder=${sortOrder.direction}`; + if (isDefinedAndNotNull(objectIds) && objectIds.length > 0) { + url += `&objectIds=${objectIds}`; } - if (isDefinedAndNotNull(sortOrder)) { - url += `&sortProperty=${sortOrder.property}&sortOrder=${sortOrder.direction}`; + if (isDefinedAndNotNull(searchText) && !isEmptyStr(searchText)) { + url += `&searchText=${searchText}`; } return this.http.get>(url, defaultHttpOptionsFromConfig(config)); } diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts index d5dc7e90b6..f66a45a178 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts @@ -74,7 +74,8 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro this.requiredValue = coerceBooleanProperty(value); } - private propagateChange = (v: any) => { }; + private propagateChange = (v: any) => { + }; constructor(private store: Store, private fb: FormBuilder, @@ -130,8 +131,8 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro writeValue(value: any | null): void { this.configurationValue = (Object.keys(value).length === 0) ? getDefaultProfileConfig() : value; this.lwm2mDeviceConfigFormGroup.patchValue({ - configurationJson: this.configurationValue - }, {emitEvent: false}); + configurationJson: this.configurationValue + }, {emitEvent: false}); this.initWriteValue(); } @@ -143,7 +144,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro property: 'id', direction: Direction.ASC }; - this.deviceProfileService.getLwm2mObjects(modelValue.objectIds, null, sortOrder).subscribe( + this.deviceProfileService.getLwm2mObjects(sortOrder, modelValue.objectIds, null).subscribe( (objectsList) => { modelValue.objectsList = objectsList; this.updateWriteValue(modelValue); @@ -300,9 +301,9 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro private addInstances = (attribute: string[], telemetry: string[], clientObserveAttrTelemetry: ObjectLwM2M[]): void => { const instancesPath = attribute.concat(telemetry) - .filter(instance => !instance.includes('/0/')) - .map(instance => this.convertPathToInstance(instance)) - .sort(); + .filter(instance => !instance.includes('/0/')) + .map(instance => this.convertPathToInstance(instance)) + .sort(); new Set(instancesPath).forEach(path => { const pathParameter = Array.from(path.split('/'), Number); diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts index d0f6c3cc47..0426f1d032 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts @@ -19,12 +19,11 @@ import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Valida import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; -import { Observable } from 'rxjs'; -import { filter, map, mergeMap, share, tap } from 'rxjs/operators'; +import { Observable, of } from 'rxjs'; +import { filter, mergeMap, share, tap } from 'rxjs/operators'; import { ObjectLwM2M } from './profile-config.models'; import { TranslateService } from '@ngx-translate/core'; import { DeviceProfileService } from '@core/http/device-profile.service'; -import { PageLink } from '@shared/models/page/page-link'; import { Direction } from '@shared/models/page/sort-order'; @Component({ @@ -115,6 +114,7 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V this.disabled = isDisabled; if (isDisabled) { this.lwm2mListFormGroup.disable({emitEvent: false}); + this.clear(); } else { this.lwm2mListFormGroup.enable({emitEvent: false}); } @@ -168,16 +168,14 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V return object ? object.name : undefined; } - // @TODO: add support page size - // @TODO: filter for id + name private fetchListObjects = (searchText?: string): Observable> => { this.searchText = searchText; - const pageLink = new PageLink(50, 0, searchText, { + const sortOrder = { property: 'name', direction: Direction.ASC - }); - return this.deviceProfileService.getLwm2mObjectsPage(pageLink, {ignoreLoading: true}).pipe( - map(pageData => pageData.data) + }; + return this.deviceProfileService.getLwm2mObjects(sortOrder, null, searchText).pipe( + mergeMap(objectsList => of(objectsList)) ); } From 6a458e85b0c0603b6fd9498ce71f0fdd9e29e54b Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Mon, 25 Jan 2021 17:05:01 +0200 Subject: [PATCH 069/249] reset password improvements --- .../java/org/thingsboard/server/dao/user/UserServiceImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java index 1f25a0f290..519092274b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java @@ -186,6 +186,7 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic public UserCredentials requestPasswordReset(TenantId tenantId, String email) { log.trace("Executing requestPasswordReset email [{}]", email); validateString(email, "Incorrect email " + email); + DataValidator.validateEmail(email); User user = userDao.findByEmail(tenantId, email); if (user == null) { throw new IncorrectParameterException(String.format("Unable to find user by email [%s]", email)); From fdfd090b0bb844e08646dd75112a5a2227c71b11 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Mon, 25 Jan 2021 17:07:14 +0200 Subject: [PATCH 070/249] UI: Fixed email validation in form reset password --- .../reset-password-request.component.html | 2 +- .../login/reset-password-request.component.ts | 22 +++++++++++-------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/ui-ngx/src/app/modules/login/pages/login/reset-password-request.component.html b/ui-ngx/src/app/modules/login/pages/login/reset-password-request.component.html index 2d20022576..8e723d15a4 100644 --- a/ui-ngx/src/app/modules/login/pages/login/reset-password-request.component.html +++ b/ui-ngx/src/app/modules/login/pages/login/reset-password-request.component.html @@ -28,7 +28,7 @@
- + login.email email diff --git a/ui-ngx/src/app/modules/login/pages/login/reset-password-request.component.ts b/ui-ngx/src/app/modules/login/pages/login/reset-password-request.component.ts index 1515c4fc34..62b8798bf8 100644 --- a/ui-ngx/src/app/modules/login/pages/login/reset-password-request.component.ts +++ b/ui-ngx/src/app/modules/login/pages/login/reset-password-request.component.ts @@ -19,7 +19,7 @@ import { AuthService } from '@core/auth/auth.service'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { PageComponent } from '@shared/components/page.component'; -import { FormBuilder } from '@angular/forms'; +import { FormBuilder, Validators } from '@angular/forms'; import { ActionNotificationShow } from '@core/notification/notification.actions'; import { TranslateService } from '@ngx-translate/core'; @@ -31,8 +31,8 @@ import { TranslateService } from '@ngx-translate/core'; export class ResetPasswordRequestComponent extends PageComponent implements OnInit { requestPasswordRequest = this.fb.group({ - email: [''] - }); + email: ['', [Validators.email, Validators.required]] + }, {updateOn: 'submit'}); constructor(protected store: Store, private authService: AuthService, @@ -45,12 +45,16 @@ export class ResetPasswordRequestComponent extends PageComponent implements OnIn } sendResetPasswordLink() { - this.authService.sendResetPasswordLink(this.requestPasswordRequest.get('email').value).subscribe( - () => { - this.store.dispatch(new ActionNotificationShow({ message: this.translate.instant('login.password-link-sent-message'), - type: 'success' })); - } - ); + if (this.requestPasswordRequest.valid) { + this.authService.sendResetPasswordLink(this.requestPasswordRequest.get('email').value).subscribe( + () => { + this.store.dispatch(new ActionNotificationShow({ + message: this.translate.instant('login.password-link-sent-message'), + type: 'success' + })); + } + ); + } } } From a4981a869f586c106ba2af4b12507d0bbc673721 Mon Sep 17 00:00:00 2001 From: AndrewVolostnykhThingsboard Date: Mon, 25 Jan 2021 18:01:17 +0200 Subject: [PATCH 071/249] highestAlarmSeverity fixed --- .../server/dao/alarm/BaseAlarmService.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java index 45478ce146..35d0619201 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java @@ -320,17 +320,29 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ boolean hasNext = true; AlarmSeverity highestSeverity = null; AlarmQuery query; - while (hasNext && AlarmSeverity.CRITICAL != highestSeverity) { + while (hasNext) { query = new AlarmQuery(entityId, nextPageLink, alarmSearchStatus, alarmStatus, false, null); PageData alarms = alarmDao.findAlarms(tenantId, query); + + if(alarms.getData().isEmpty()) { + return null; + } if (alarms.hasNext()) { nextPageLink = nextPageLink.nextPageLink(); + } else { + hasNext = false; } + AlarmSeverity severity = detectHighestSeverity(alarms.getData()); if (severity == null) { continue; } - if (severity == AlarmSeverity.CRITICAL || highestSeverity == null) { + + if(severity == AlarmSeverity.CRITICAL) { + return severity; + } + + if (highestSeverity == null) { highestSeverity = severity; } else { highestSeverity = highestSeverity.compareTo(severity) < 0 ? highestSeverity : severity; From ca940ba1b6619802b9c1b6abcf26e0a1e3416588 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Mon, 25 Jan 2021 19:54:01 +0200 Subject: [PATCH 072/249] UI: Refactoring LwM2M --- ...ofile-transport-configuration.component.ts | 134 +++++------------- .../lwm2m/lwm2m-object-list.component.ts | 9 +- .../lwm2m-observe-attr-telemetry.component.ts | 4 +- 3 files changed, 44 insertions(+), 103 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts index f66a45a178..86743074f9 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts @@ -75,15 +75,15 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } private propagateChange = (v: any) => { - }; + } constructor(private store: Store, private fb: FormBuilder, private deviceProfileService: DeviceProfileService, @Inject(WINDOW) private window: Window) { this.lwm2mDeviceProfileFormGroup = this.fb.group({ - objectIds: [{}, Validators.required], - observeAttrTelemetry: [{clientLwM2M: []}, Validators.required], + objectIds: [[], Validators.required], + observeAttrTelemetry: [null, Validators.required], shortId: [null, Validators.required], lifetime: [null, Validators.required], defaultMinPeriod: [null, Validators.required], @@ -95,10 +95,10 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro this.lwm2mDeviceConfigFormGroup = this.fb.group({ configurationJson: [null, Validators.required] }); - this.lwm2mDeviceProfileFormGroup.valueChanges.subscribe(() => { + this.lwm2mDeviceProfileFormGroup.valueChanges.subscribe((value) => { console.warn('main form'); if (!this.disabled) { - this.updateModel(); + this.updateDeviceProfileValue(value); } }); this.lwm2mDeviceConfigFormGroup.valueChanges.subscribe(() => { @@ -159,7 +159,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro const objectsList = value.objectsList; this.lwm2mDeviceProfileFormGroup.patchValue({ objectIds: value, - observeAttrTelemetry: {clientLwM2M: this.getObserveAttrTelemetryObjects(objectsList)}, + observeAttrTelemetry: this.getObserveAttrTelemetryObjects(objectsList), shortId: this.configurationValue.bootstrap.servers.shortId, lifetime: this.configurationValue.bootstrap.servers.lifetime, defaultMinPeriod: this.configurationValue.bootstrap.servers.defaultMinPeriod, @@ -173,9 +173,8 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro private updateModel = (): void => { let configuration: DeviceProfileTransportConfiguration = null; - if (this.lwm2mDeviceConfigFormGroup.valid) { - this.upDateValueToJson(); - configuration = this.lwm2mDeviceConfigFormGroup.getRawValue().configurationJson; + if (this.lwm2mDeviceConfigFormGroup.valid && this.lwm2mDeviceProfileFormGroup.valid) { + configuration = this.lwm2mDeviceConfigFormGroup.value.configurationJson; configuration.type = DeviceTransportType.LWM2M; } this.propagateChange(configuration); @@ -183,89 +182,31 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro private updateObserveAttrTelemetryObjectFormGroup = (objectsList: ObjectLwM2M[]): void => { this.lwm2mDeviceProfileFormGroup.patchValue({ - observeAttrTelemetry: {clientLwM2M: this.getObserveAttrTelemetryObjects(objectsList)} + observeAttrTelemetry: this.getObserveAttrTelemetryObjects(objectsList) }, {emitEvent: false}); - this.lwm2mDeviceProfileFormGroup.get('observeAttrTelemetry').markAsPristine({ - onlySelf: true - }); - } - - private upDateValueToJson = (): void => { - this.upDateValueToJsonTab0(); - this.upDateValueToJsonTab1(); - } - - private upDateValueToJsonTab0 = (): void => { - if (!this.lwm2mDeviceProfileFormGroup.get('observeAttrTelemetry').pristine) { - this.upDateObserveAttrTelemetryFromGroupToJson( - this.lwm2mDeviceProfileFormGroup.get('observeAttrTelemetry').value.clientLwM2M - ); - this.lwm2mDeviceProfileFormGroup.get('observeAttrTelemetry').markAsPristine({ - onlySelf: true - }); - this.upDateJsonAllConfig(); - } - } - - private upDateValueToJsonTab1 = (): void => { - this.upDateValueServersToJson(); - if (!this.lwm2mDeviceProfileFormGroup.get('bootstrapServer').pristine) { - this.configurationValue.bootstrap.bootstrapServer = this.lwm2mDeviceProfileFormGroup.get('bootstrapServer').value; - this.lwm2mDeviceProfileFormGroup.get('bootstrapServer').markAsPristine({ - onlySelf: true - }); - this.upDateJsonAllConfig(); - } - if (!this.lwm2mDeviceProfileFormGroup.get('lwm2mServer').pristine) { - this.configurationValue.bootstrap.lwm2mServer = this.lwm2mDeviceProfileFormGroup.get('lwm2mServer').value; - this.lwm2mDeviceProfileFormGroup.get('lwm2mServer').markAsPristine({ - onlySelf: true - }); - this.upDateJsonAllConfig(); - } - } - - private upDateValueServersToJson = (): void => { - const bootstrapServers = this.configurationValue.bootstrap.servers; - if (!this.lwm2mDeviceProfileFormGroup.get('shortId').pristine) { - bootstrapServers.shortId = this.lwm2mDeviceProfileFormGroup.get('shortId').value; - this.lwm2mDeviceProfileFormGroup.get('shortId').markAsPristine({ - onlySelf: true - }); - this.upDateJsonAllConfig(); - } - if (!this.lwm2mDeviceProfileFormGroup.get('lifetime').pristine) { - bootstrapServers.lifetime = this.lwm2mDeviceProfileFormGroup.get('lifetime').value; - this.lwm2mDeviceProfileFormGroup.get('lifetime').markAsPristine({ - onlySelf: true - }); - this.upDateJsonAllConfig(); - } - if (!this.lwm2mDeviceProfileFormGroup.get('defaultMinPeriod').pristine) { - bootstrapServers.defaultMinPeriod = this.lwm2mDeviceProfileFormGroup.get('defaultMinPeriod').value; - this.lwm2mDeviceProfileFormGroup.get('defaultMinPeriod').markAsPristine({ - onlySelf: true - }); - this.upDateJsonAllConfig(); - } - if (!this.lwm2mDeviceProfileFormGroup.get('notifIfDisabled').pristine) { - bootstrapServers.notifIfDisabled = this.lwm2mDeviceProfileFormGroup.get('notifIfDisabled').value; - this.lwm2mDeviceProfileFormGroup.get('notifIfDisabled').markAsPristine({ - onlySelf: true - }); - this.upDateJsonAllConfig(); - } - if (!this.lwm2mDeviceProfileFormGroup.get('binding').pristine) { - bootstrapServers.binding = this.lwm2mDeviceProfileFormGroup.get('binding').value; - this.lwm2mDeviceProfileFormGroup.get('binding').markAsPristine({ - onlySelf: true - }); + // this.lwm2mDeviceProfileFormGroup.get('observeAttrTelemetry').markAsPristine({ + // onlySelf: true + // }); + } + + private updateDeviceProfileValue(config): void { + if (this.lwm2mDeviceProfileFormGroup.valid) { + this.upDateObserveAttrTelemetryFromGroupToJson(config.observeAttrTelemetry.clientLwM2M); + this.configurationValue.bootstrap.bootstrapServer = config.bootstrapServer; + this.configurationValue.bootstrap.lwm2mServer = config.lwm2mServer; + const bootstrapServers = this.configurationValue.bootstrap.servers; + bootstrapServers.shortId = config.shortId; + bootstrapServers.lifetime = config.lifetime; + bootstrapServers.defaultMinPeriod = config.defaultMinPeriod; + bootstrapServers.notifIfDisabled = config.notifIfDisabled; + bootstrapServers.binding = config.binding; this.upDateJsonAllConfig(); + this.updateModel(); } } - private getObserveAttrTelemetryObjects = (listObject: ObjectLwM2M[]): ObjectLwM2M [] => { + private getObserveAttrTelemetryObjects = (listObject: ObjectLwM2M[]): object => { const clientObserveAttrTelemetry = listObject; if (this.configurationValue[this.observeAttr]) { const observeArray = this.configurationValue[this.observeAttr][this.observe]; @@ -291,7 +232,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro clientObserveAttrTelemetry.forEach(obj => { obj.instances.sort((a, b) => a.id - b.id); }); - return clientObserveAttrTelemetry; + return {clientLwM2M: clientObserveAttrTelemetry}; } private includesNotZeroInstance = (attribute: string[], telemetry: string[]): boolean => { @@ -480,7 +421,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro return pathParameterIndexes; } - private getObjectsFromJsonAllConfig = (): number [] => { + private getObjectsFromJsonAllConfig = (): number[] => { const objectsIds = new Set(); if (this.configurationValue[this.observeAttr]) { if (this.configurationValue[this.observeAttr][this.observe]) { @@ -503,20 +444,17 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } private upDateJsonAllConfig = (): void => { - this.lwm2mDeviceProfileFormGroup.patchValue({ + this.lwm2mDeviceConfigFormGroup.patchValue({ configurationJson: this.configurationValue }, {emitEvent: false}); - this.lwm2mDeviceProfileFormGroup.markAsPristine({ - onlySelf: true - }); } addObjectsList = (value: ObjectLwM2M[]): void => { - this.updateObserveAttrTelemetryObjectFormGroup(deepClone(value)); + this.updateObserveAttrTelemetryObjectFormGroup(value); } removeObjectsList = (value: ObjectLwM2M): void => { - const objectsOld = deepClone(this.lwm2mDeviceProfileFormGroup.get('observeAttrTelemetry').value.clientLwM2M); + const objectsOld = this.lwm2mDeviceProfileFormGroup.get('observeAttrTelemetry').value.clientLwM2M; const isIdIndex = (element) => element.id === value.id; const index = objectsOld.findIndex(isIdIndex); if (index >= 0) { @@ -526,25 +464,23 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro this.removeObserveAttrTelemetryFromJson(this.observe, value.id); this.removeObserveAttrTelemetryFromJson(this.telemetry, value.id); this.removeObserveAttrTelemetryFromJson(this.attribute, value.id); - this.removeObserveAttrTelemetryFromJson(this.attribute, value.id); this.removeKeyNameFromJson(value.id); this.upDateJsonAllConfig(); } private removeObserveAttrTelemetryFromJson = (observeAttrTel: string, id: number): void => { - const isIdIndex = (element) => Array.from(element.substring(1).split('/'), Number)[0] === id; + const isIdIndex = (element: string) => element.startsWith(`/${id}`); let index = this.configurationValue[this.observeAttr][observeAttrTel].findIndex(isIdIndex); while (index >= 0) { this.configurationValue[this.observeAttr][observeAttrTel].splice(index, 1); - index = this.configurationValue[this.observeAttr][observeAttrTel].findIndex(isIdIndex); + index = this.configurationValue[this.observeAttr][observeAttrTel].findIndex(isIdIndex, index); } } private removeKeyNameFromJson = (id: number): void => { const keyNameJson = this.configurationValue[this.observeAttr][this.keyName]; Object.keys(keyNameJson).forEach(key => { - const idKey = Array.from(key.substring(1).split('/'), Number)[0]; - if (idKey === id) { + if (key.startsWith(`/${id}`)) { delete keyNameJson[key]; } }); diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts index 0426f1d032..d868d6b04f 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts @@ -25,6 +25,7 @@ import { ObjectLwM2M } from './profile-config.models'; import { TranslateService } from '@ngx-translate/core'; import { DeviceProfileService } from '@core/http/device-profile.service'; import { Direction } from '@shared/models/page/sort-order'; +import { isDefined } from '@core/utils'; @Component({ selector: 'tb-profile-lwm2m-object-list', @@ -114,7 +115,9 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V this.disabled = isDisabled; if (isDisabled) { this.lwm2mListFormGroup.disable({emitEvent: false}); - this.clear(); + if (isDefined(this.objectInput)) { + this.clear(); + } } else { this.lwm2mListFormGroup.enable({emitEvent: false}); } @@ -144,7 +147,7 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V this.lwm2mListFormGroup.get('objectsList').setValue(this.objectsList); this.addList.next(this.objectsList); } - this.propagateChange(this.modelValue); + // this.propagateChange(this.modelValue); this.clear(); } @@ -159,7 +162,7 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V if (!this.modelValue.length) { this.modelValue = null; } - this.propagateChange(this.modelValue); + // this.propagateChange(this.modelValue); this.clear(); } } diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts index 4122971e50..4eeeb4b3e5 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts @@ -124,7 +124,9 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor } writeValue(value: any): void { - this.buildClientObjectsLwM2M(value.clientLwM2M); + if (isDefinedAndNotNull(value)) { + this.buildClientObjectsLwM2M(value.clientLwM2M); + } } private buildClientObjectsLwM2M = (objectsLwM2M: ObjectLwM2M []): void => { From 61723da3910222caae4acc87fc414fc794fdf66c Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 26 Jan 2021 10:17:52 +0200 Subject: [PATCH 073/249] Version set to 3.3.0-SNAPSHOT --- application/pom.xml | 2 +- common/actor/pom.xml | 2 +- common/dao-api/pom.xml | 2 +- common/data/pom.xml | 2 +- common/message/pom.xml | 2 +- common/pom.xml | 2 +- common/queue/pom.xml | 2 +- common/stats/pom.xml | 2 +- common/transport/coap/pom.xml | 2 +- common/transport/http/pom.xml | 2 +- common/transport/mqtt/pom.xml | 2 +- common/transport/pom.xml | 2 +- common/transport/transport-api/pom.xml | 2 +- common/util/pom.xml | 2 +- dao/pom.xml | 2 +- msa/black-box-tests/pom.xml | 2 +- msa/js-executor/package.json | 2 +- msa/js-executor/pom.xml | 2 +- msa/pom.xml | 2 +- msa/tb-node/pom.xml | 2 +- msa/tb/pom.xml | 2 +- msa/transport/coap/pom.xml | 2 +- msa/transport/http/pom.xml | 2 +- msa/transport/mqtt/pom.xml | 2 +- msa/transport/pom.xml | 2 +- msa/web-ui/package.json | 2 +- msa/web-ui/pom.xml | 2 +- netty-mqtt/pom.xml | 4 ++-- pom.xml | 2 +- rest-client/pom.xml | 2 +- rule-engine/pom.xml | 2 +- rule-engine/rule-engine-api/pom.xml | 2 +- rule-engine/rule-engine-components/pom.xml | 2 +- tools/pom.xml | 2 +- transport/coap/pom.xml | 2 +- transport/http/pom.xml | 2 +- transport/mqtt/pom.xml | 2 +- transport/pom.xml | 2 +- ui-ngx/package.json | 2 +- ui-ngx/pom.xml | 2 +- 40 files changed, 41 insertions(+), 41 deletions(-) diff --git a/application/pom.xml b/application/pom.xml index c1a49b09e3..62fd69d4f4 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT thingsboard application diff --git a/common/actor/pom.xml b/common/actor/pom.xml index a421b8cef4..6609648e7c 100644 --- a/common/actor/pom.xml +++ b/common/actor/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT common org.thingsboard.common diff --git a/common/dao-api/pom.xml b/common/dao-api/pom.xml index 99ec232953..b427846d91 100644 --- a/common/dao-api/pom.xml +++ b/common/dao-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT common org.thingsboard.common diff --git a/common/data/pom.xml b/common/data/pom.xml index 4454e628c0..6d484bd107 100644 --- a/common/data/pom.xml +++ b/common/data/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT common org.thingsboard.common diff --git a/common/message/pom.xml b/common/message/pom.xml index a9366c9de2..8bc2653bb0 100644 --- a/common/message/pom.xml +++ b/common/message/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT common org.thingsboard.common diff --git a/common/pom.xml b/common/pom.xml index 186c5ecdd8..11b1e02477 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT thingsboard common diff --git a/common/queue/pom.xml b/common/queue/pom.xml index e4d9e1bf20..4c3eb4aeba 100644 --- a/common/queue/pom.xml +++ b/common/queue/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT common org.thingsboard.common diff --git a/common/stats/pom.xml b/common/stats/pom.xml index 830c5bb3b5..205f5c1dc6 100644 --- a/common/stats/pom.xml +++ b/common/stats/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT common org.thingsboard.common diff --git a/common/transport/coap/pom.xml b/common/transport/coap/pom.xml index 2d7c0df235..a8a1ac452a 100644 --- a/common/transport/coap/pom.xml +++ b/common/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/http/pom.xml b/common/transport/http/pom.xml index 6f5076adc0..2c8a9bbeae 100644 --- a/common/transport/http/pom.xml +++ b/common/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/mqtt/pom.xml b/common/transport/mqtt/pom.xml index 0d231581b9..18c2126f07 100644 --- a/common/transport/mqtt/pom.xml +++ b/common/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/pom.xml b/common/transport/pom.xml index 957b0d518c..667a257a0b 100644 --- a/common/transport/pom.xml +++ b/common/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT common org.thingsboard.common diff --git a/common/transport/transport-api/pom.xml b/common/transport/transport-api/pom.xml index 6c8fdafd84..69a03dd170 100644 --- a/common/transport/transport-api/pom.xml +++ b/common/transport/transport-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/util/pom.xml b/common/util/pom.xml index 1e0ceb049d..68ad14d2eb 100644 --- a/common/util/pom.xml +++ b/common/util/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT common org.thingsboard.common diff --git a/dao/pom.xml b/dao/pom.xml index 1acbef4c42..e9ee4e9219 100644 --- a/dao/pom.xml +++ b/dao/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT thingsboard dao diff --git a/msa/black-box-tests/pom.xml b/msa/black-box-tests/pom.xml index 9cfaea0ed9..9af00d44c7 100644 --- a/msa/black-box-tests/pom.xml +++ b/msa/black-box-tests/pom.xml @@ -21,7 +21,7 @@ org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/js-executor/package.json b/msa/js-executor/package.json index 8e7ba6d96e..75f009880b 100644 --- a/msa/js-executor/package.json +++ b/msa/js-executor/package.json @@ -1,7 +1,7 @@ { "name": "thingsboard-js-executor", "private": true, - "version": "3.2.1", + "version": "3.3.0", "description": "ThingsBoard JavaScript Executor Microservice", "main": "server.js", "bin": "server.js", diff --git a/msa/js-executor/pom.xml b/msa/js-executor/pom.xml index 3e90099a76..a254b1acde 100644 --- a/msa/js-executor/pom.xml +++ b/msa/js-executor/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/pom.xml b/msa/pom.xml index 686526d7b0..4639cae78f 100644 --- a/msa/pom.xml +++ b/msa/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT thingsboard msa diff --git a/msa/tb-node/pom.xml b/msa/tb-node/pom.xml index c9c0a2d4a2..133b81c79d 100644 --- a/msa/tb-node/pom.xml +++ b/msa/tb-node/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/tb/pom.xml b/msa/tb/pom.xml index 5803f70bce..efb9a709e9 100644 --- a/msa/tb/pom.xml +++ b/msa/tb/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/transport/coap/pom.xml b/msa/transport/coap/pom.xml index 056c38605c..1285cca0ce 100644 --- a/msa/transport/coap/pom.xml +++ b/msa/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/http/pom.xml b/msa/transport/http/pom.xml index 3ba39a92e2..da0688b545 100644 --- a/msa/transport/http/pom.xml +++ b/msa/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/mqtt/pom.xml b/msa/transport/mqtt/pom.xml index 279a03c03d..782b6a228a 100644 --- a/msa/transport/mqtt/pom.xml +++ b/msa/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/pom.xml b/msa/transport/pom.xml index 6fdedfbfcf..3971858ce5 100644 --- a/msa/transport/pom.xml +++ b/msa/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/web-ui/package.json b/msa/web-ui/package.json index 792926a86d..3897c31f5e 100644 --- a/msa/web-ui/package.json +++ b/msa/web-ui/package.json @@ -1,7 +1,7 @@ { "name": "thingsboard-web-ui", "private": true, - "version": "3.2.1", + "version": "3.3.0", "description": "ThingsBoard Web UI Microservice", "main": "server.js", "bin": "server.js", diff --git a/msa/web-ui/pom.xml b/msa/web-ui/pom.xml index ffd1ba2e16..85f5db6ce3 100644 --- a/msa/web-ui/pom.xml +++ b/msa/web-ui/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT msa org.thingsboard.msa diff --git a/netty-mqtt/pom.xml b/netty-mqtt/pom.xml index f778d83c44..46ab5af314 100644 --- a/netty-mqtt/pom.xml +++ b/netty-mqtt/pom.xml @@ -19,11 +19,11 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT thingsboard netty-mqtt - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT jar Netty MQTT Client diff --git a/pom.xml b/pom.xml index 4ec162be8f..83899b46cb 100755 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT pom Thingsboard diff --git a/rest-client/pom.xml b/rest-client/pom.xml index d170dec0e2..e45db432d8 100644 --- a/rest-client/pom.xml +++ b/rest-client/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT thingsboard rest-client diff --git a/rule-engine/pom.xml b/rule-engine/pom.xml index 2e968bfb46..d4af78f871 100644 --- a/rule-engine/pom.xml +++ b/rule-engine/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT thingsboard rule-engine diff --git a/rule-engine/rule-engine-api/pom.xml b/rule-engine/rule-engine-api/pom.xml index 613493b0d5..c303c6984e 100644 --- a/rule-engine/rule-engine-api/pom.xml +++ b/rule-engine/rule-engine-api/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT rule-engine org.thingsboard.rule-engine diff --git a/rule-engine/rule-engine-components/pom.xml b/rule-engine/rule-engine-components/pom.xml index 48863dac3e..0084e0e531 100644 --- a/rule-engine/rule-engine-components/pom.xml +++ b/rule-engine/rule-engine-components/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT rule-engine org.thingsboard.rule-engine diff --git a/tools/pom.xml b/tools/pom.xml index 18861cffe7..c7fcf277ea 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT thingsboard tools diff --git a/transport/coap/pom.xml b/transport/coap/pom.xml index 05eec2e09a..440be0ecea 100644 --- a/transport/coap/pom.xml +++ b/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/http/pom.xml b/transport/http/pom.xml index 252800254f..bb9262de66 100644 --- a/transport/http/pom.xml +++ b/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/mqtt/pom.xml b/transport/mqtt/pom.xml index 1a026f7c32..579d514729 100644 --- a/transport/mqtt/pom.xml +++ b/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/pom.xml b/transport/pom.xml index bcafb9a184..81a5ce8116 100644 --- a/transport/pom.xml +++ b/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT thingsboard transport diff --git a/ui-ngx/package.json b/ui-ngx/package.json index a2449a2a7f..13913d8d97 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -1,6 +1,6 @@ { "name": "thingsboard", - "version": "3.2.1", + "version": "3.3.0", "scripts": { "ng": "ng", "start": "node --max_old_space_size=8048 ./node_modules/@angular/cli/bin/ng serve --host 0.0.0.0 --open", diff --git a/ui-ngx/pom.xml b/ui-ngx/pom.xml index fdde603242..fb8c809260 100644 --- a/ui-ngx/pom.xml +++ b/ui-ngx/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT thingsboard org.thingsboard From 3c558a7d2a98cc1baffb5470fbb7e00819b799da Mon Sep 17 00:00:00 2001 From: AndrewVolostnykhThingsboard Date: Tue, 26 Jan 2021 11:45:57 +0200 Subject: [PATCH 074/249] getHighestAlarmSeverity: cleared unwanted code --- .../server/dao/alarm/BaseAlarmService.java | 33 +++---------------- 1 file changed, 5 insertions(+), 28 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java index 35d0619201..0c781478d5 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java @@ -28,12 +28,7 @@ import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.common.data.Tenant; -import org.thingsboard.server.common.data.alarm.Alarm; -import org.thingsboard.server.common.data.alarm.AlarmInfo; -import org.thingsboard.server.common.data.alarm.AlarmQuery; -import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; -import org.thingsboard.server.common.data.alarm.AlarmSeverity; -import org.thingsboard.server.common.data.alarm.AlarmStatus; +import org.thingsboard.server.common.data.alarm.*; import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; @@ -41,13 +36,8 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.query.AlarmData; -import org.thingsboard.server.common.data.query.AlarmDataPageLink; import org.thingsboard.server.common.data.query.AlarmDataQuery; -import org.thingsboard.server.common.data.relation.EntityRelation; -import org.thingsboard.server.common.data.relation.EntityRelationsQuery; -import org.thingsboard.server.common.data.relation.EntitySearchDirection; -import org.thingsboard.server.common.data.relation.RelationTypeGroup; -import org.thingsboard.server.common.data.relation.RelationsSearchParameters; +import org.thingsboard.server.common.data.relation.*; import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.exception.DataValidationException; @@ -57,13 +47,7 @@ import org.thingsboard.server.dao.tenant.TenantDao; import javax.annotation.Nullable; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; +import java.util.*; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -320,13 +304,10 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ boolean hasNext = true; AlarmSeverity highestSeverity = null; AlarmQuery query; - while (hasNext) { + while (hasNext && AlarmSeverity.CRITICAL != highestSeverity) { query = new AlarmQuery(entityId, nextPageLink, alarmSearchStatus, alarmStatus, false, null); PageData alarms = alarmDao.findAlarms(tenantId, query); - if(alarms.getData().isEmpty()) { - return null; - } if (alarms.hasNext()) { nextPageLink = nextPageLink.nextPageLink(); } else { @@ -338,11 +319,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ continue; } - if(severity == AlarmSeverity.CRITICAL) { - return severity; - } - - if (highestSeverity == null) { + if (severity == AlarmSeverity.CRITICAL || highestSeverity == null) { highestSeverity = severity; } else { highestSeverity = highestSeverity.compareTo(severity) < 0 ? highestSeverity : severity; From f770f407971c6d99e39ce488fe29cf08c9a76442 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 26 Jan 2021 14:40:32 +0200 Subject: [PATCH 075/249] Lwm2m: front: update filter for models --- ...ofile-transport-configuration.component.ts | 4 -- .../lwm2m/lwm2m-object-list.component.ts | 45 +++++++++++++------ 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts index 86743074f9..f7d01db377 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts @@ -96,7 +96,6 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro configurationJson: [null, Validators.required] }); this.lwm2mDeviceProfileFormGroup.valueChanges.subscribe((value) => { - console.warn('main form'); if (!this.disabled) { this.updateDeviceProfileValue(value); } @@ -185,9 +184,6 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro observeAttrTelemetry: this.getObserveAttrTelemetryObjects(objectsList) }, {emitEvent: false}); - // this.lwm2mDeviceProfileFormGroup.get('observeAttrTelemetry').markAsPristine({ - // onlySelf: true - // }); } private updateDeviceProfileValue(config): void { diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts index d868d6b04f..625f9c77d9 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts @@ -20,12 +20,12 @@ import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { Observable, of } from 'rxjs'; -import { filter, mergeMap, share, tap } from 'rxjs/operators'; +import { filter, map, mergeMap, tap } from 'rxjs/operators'; import { ObjectLwM2M } from './profile-config.models'; import { TranslateService } from '@ngx-translate/core'; import { DeviceProfileService } from '@core/http/device-profile.service'; import { Direction } from '@shared/models/page/sort-order'; -import { isDefined } from '@core/utils'; +import { isDefined, isDefinedAndNotNull, isEmptyStr } from '@core/utils'; @Component({ selector: 'tb-profile-lwm2m-object-list', @@ -42,6 +42,7 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V private requiredValue: boolean; private dirty = false; + private allObjectsList: Observable>; lwm2mListFormGroup: FormGroup; modelValue: Array | null; @@ -71,7 +72,8 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V @ViewChild('objectInput') objectInput: ElementRef; - private propagateChange = (v: any) => { }; + private propagateChange = (v: any) => { + }; constructor(private store: Store, public translate: TranslateService, @@ -106,8 +108,8 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V } }), filter((value) => typeof value === 'string'), - mergeMap(name => this.fetchListObjects(name)), - share() + // map(value => value ? value : ''), + mergeMap(searchText => this.fetchListObjects(searchText)) ); } @@ -147,7 +149,6 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V this.lwm2mListFormGroup.get('objectsList').setValue(this.objectsList); this.addList.next(this.objectsList); } - // this.propagateChange(this.modelValue); this.clear(); } @@ -162,7 +163,6 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V if (!this.modelValue.length) { this.modelValue = null; } - // this.propagateChange(this.modelValue); this.clear(); } } @@ -173,15 +173,34 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V private fetchListObjects = (searchText?: string): Observable> => { this.searchText = searchText; - const sortOrder = { - property: 'name', - direction: Direction.ASC - }; - return this.deviceProfileService.getLwm2mObjects(sortOrder, null, searchText).pipe( - mergeMap(objectsList => of(objectsList)) + const filters = {names: [], ids: []}; + if (isDefinedAndNotNull(searchText) && !isEmptyStr(searchText)) { + const ids = searchText.match(/\d+/g); + filters.ids = isDefinedAndNotNull(ids) ? ids.map(Number) as [] : filters.ids; + const names = searchText.trim().split(" ") as []; + filters.names = names; + } + const predicate = objectLwM2M => filters.names.filter(word => objectLwM2M.name.toUpperCase().includes(word.toUpperCase())).length>0 + || filters.ids.includes(objectLwM2M.id); + return this.getListModels().pipe( + map(objectLwM2Ms => searchText ? objectLwM2Ms.filter(predicate) : objectLwM2Ms) ); } + private getListModels(): Observable> { + if (!this.allObjectsList) { + const sortOrder = { + property: 'name', + direction: Direction.ASC + }; + this.allObjectsList = this.deviceProfileService.getLwm2mObjects(sortOrder, null, null).pipe( + mergeMap(objectsList => of(objectsList)) + ); + } + return this.allObjectsList; + } + + onFocus = (): void => { if (this.dirty) { this.lwm2mListFormGroup.get('objectLwm2m').updateValueAndValidity({onlySelf: true, emitEvent: true}); From c14e2c81b1840a9160496b0baa431fb1e13d66be Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Tue, 26 Jan 2021 19:20:36 +0200 Subject: [PATCH 076/249] UI: Refactoring LwM2M --- ...ofile-transport-configuration.component.ts | 118 +++++++----------- .../lwm2m/lwm2m-object-list.component.ts | 78 ++++++------ ...wm2m-observe-attr-telemetry.component.html | 25 ++-- .../lwm2m-observe-attr-telemetry.component.ts | 2 +- 4 files changed, 94 insertions(+), 129 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts index f7d01db377..e9b6b17edc 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts @@ -82,7 +82,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro private deviceProfileService: DeviceProfileService, @Inject(WINDOW) private window: Window) { this.lwm2mDeviceProfileFormGroup = this.fb.group({ - objectIds: [[], Validators.required], + objectIds: [null, Validators.required], observeAttrTelemetry: [null, Validators.required], shortId: [null, Validators.required], lifetime: [null, Validators.required], @@ -96,15 +96,10 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro configurationJson: [null, Validators.required] }); this.lwm2mDeviceProfileFormGroup.valueChanges.subscribe((value) => { - if (!this.disabled) { - this.updateDeviceProfileValue(value); - } + this.updateDeviceProfileValue(value); }); this.lwm2mDeviceConfigFormGroup.valueChanges.subscribe(() => { - console.warn('config form'); - if (!this.disabled) { - this.updateModel(); - } + this.updateModel(); }); this.sortFunction = this.sortObjectKeyPathJson; } @@ -188,7 +183,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro private updateDeviceProfileValue(config): void { if (this.lwm2mDeviceProfileFormGroup.valid) { - this.upDateObserveAttrTelemetryFromGroupToJson(config.observeAttrTelemetry.clientLwM2M); + this.updateObserveAttrTelemetryFromGroupToJson(config.observeAttrTelemetry.clientLwM2M); this.configurationValue.bootstrap.bootstrapServer = config.bootstrapServer; this.configurationValue.bootstrap.lwm2mServer = config.lwm2mServer; const bootstrapServers = this.configurationValue.bootstrap.servers; @@ -225,9 +220,6 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro this.updateKeyNameObjects(keyNameJson, clientObserveAttrTelemetry); } } - clientObserveAttrTelemetry.forEach(obj => { - obj.instances.sort((a, b) => a.id - b.id); - }); return {clientLwM2M: clientObserveAttrTelemetry}; } @@ -239,8 +231,8 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro private addInstances = (attribute: string[], telemetry: string[], clientObserveAttrTelemetry: ObjectLwM2M[]): void => { const instancesPath = attribute.concat(telemetry) .filter(instance => !instance.includes('/0/')) - .map(instance => this.convertPathToInstance(instance)) - .sort(); + .map(instance => instance.slice(1, instance.lastIndexOf('/'))) + .sort(this.sortPath); new Set(instancesPath).forEach(path => { const pathParameter = Array.from(path.split('/'), Number); @@ -253,24 +245,14 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro }); } - private convertPathToInstance = (path: string): string => { - const [objectId, instanceId] = path.substring(1).split('/'); - return `${objectId}/${instanceId}`; - } - private updateObserveAttrTelemetryObjects = (parameters: string[], clientObserveAttrTelemetry: ObjectLwM2M[], nameParameter: string): void => { parameters.forEach(parameter => { const [objectId, instanceId, resourceId] = Array.from(parameter.substring(1).split('/'), Number); - clientObserveAttrTelemetry - .forEach(key => { - if (key.id === objectId) { - const instance = key.instances.find(itrInstance => itrInstance.id === instanceId); - if (isDefinedAndNotNull(instance)) { - instance.resources.find(resource => resource.id === resourceId)[nameParameter] = true; - } - } - }); + clientObserveAttrTelemetry.find(objectLwm2m => objectLwm2m.id === objectId) + .instances.find(itrInstance => itrInstance.id === instanceId) + .resources.find(resource => resource.id === resourceId) + [nameParameter] = true; }); } @@ -278,62 +260,60 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro const keyName = JSON.parse(JSON.stringify(nameJson)); Object.keys(keyName).forEach(key => { const [objectId, instanceId, resourceId] = Array.from(key.substring(1).split('/'), Number); - clientObserveAttrTelemetry - .forEach(object => { - if (object.id === objectId) { - object.instances - .find(instance => instance.id === instanceId).resources - .find(resource => resource.id === resourceId).keyName = keyName[key]; - } - }); + clientObserveAttrTelemetry.find(objectLwm2m => objectLwm2m.id === objectId) + .instances.find(instance => instance.id === instanceId) + .resources.find(resource => resource.id === resourceId) + .keyName = keyName[key]; }); } - private upDateObserveAttrTelemetryFromGroupToJson = (val: ObjectLwM2M[]): void => { + private updateObserveAttrTelemetryFromGroupToJson = (val: ObjectLwM2M[]): void => { const observeArray: Array = []; const attributeArray: Array = []; const telemetryArray: Array = []; const observeJson: ObjectLwM2M[] = JSON.parse(JSON.stringify(val)); + const paths = new Set(); let pathObj; let pathInst; let pathRes; observeJson.forEach(obj => { - Object.entries(obj).forEach(([key, value]) => { + for (const [key, value] of Object.entries(obj)) { if (key === 'id') { pathObj = value; } if (key === 'instances') { - const instancesJson = JSON.parse(JSON.stringify(value)) as Instance[]; + const instancesJson = value as Instance[]; if (instancesJson.length > 0) { instancesJson.forEach(instance => { - Object.entries(instance).forEach(([instanceKey, instanceValue]) => { + for (const [instanceKey, instanceValue] of Object.entries(instance)) { if (instanceKey === 'id') { pathInst = instanceValue; } if (instanceKey === 'resources') { - const resourcesJson = JSON.parse(JSON.stringify(instanceValue)) as ResourceLwM2M[]; + const resourcesJson = instanceValue as ResourceLwM2M[]; if (resourcesJson.length > 0) { resourcesJson.forEach(res => { - Object.entries(res).forEach(([resourceKey, resourceValue]) => { + for (const [resourceKey, idResource] of Object.entries(res)) { if (resourceKey === 'id') { - // pathRes = resourceValue - pathRes = '/' + pathObj + '/' + pathInst + '/' + resourceValue; - } else if (resourceKey === 'observe' && resourceValue) { + pathRes = `/${pathObj}/${pathInst}/${idResource}`; + } else if (resourceKey === 'observe' && idResource) { observeArray.push(pathRes); - } else if (resourceKey === 'attribute' && resourceValue) { + } else if (resourceKey === 'attribute' && idResource) { attributeArray.push(pathRes); - } else if (resourceKey === 'telemetry' && resourceValue) { + paths.add(pathRes); + } else if (resourceKey === 'telemetry' && idResource) { telemetryArray.push(pathRes); + paths.add(pathRes); } - }); + } }); } } - }); + } }); } } - }); + } }); if (isUndefined(this.configurationValue[this.observeAttr])) { this.configurationValue[this.observeAttr] = { @@ -346,7 +326,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro this.configurationValue[this.observeAttr][this.attribute] = attributeArray; this.configurationValue[this.observeAttr][this.telemetry] = telemetryArray; } - this.updateKeyName(); + this.updateKeyName(paths); } sortObjectKeyPathJson = (key: string, value: object): object => { @@ -366,23 +346,13 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } private sortPath = (a, b): number => { - const aLC = Array.from(a.substring(1).split('/'), Number); - const bLC = Array.from(b.substring(1).split('/'), Number); - return aLC[0] === bLC[0] ? aLC[1] - bLC[1] : aLC[0] - bLC[0]; + return a.localeCompare(b, undefined, { + numeric: true, + sensitivity: 'base' + }); } - private updateKeyName = (): void => { - const paths = new Set(); - if (this.configurationValue[this.observeAttr][this.attribute]) { - this.configurationValue[this.observeAttr][this.attribute].forEach(path => { - paths.add(path); - }); - } - if (this.configurationValue[this.observeAttr][this.telemetry]) { - this.configurationValue[this.observeAttr][this.telemetry].forEach(path => { - paths.add(path); - }); - } + private updateKeyName = (paths: Set): void => { const keyNameNew = {}; paths.forEach(path => { const pathParameter = this.findIndexesForIds(path); @@ -395,19 +365,19 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } private findIndexesForIds = (path: string): number[] => { - const pathParameter = Array.from(path.substring(1).split('/'), Number); + const [objectId, instanceId, resourceId] = Array.from(path.substring(1).split('/'), Number); + // TODO: All paths to map const pathParameterIndexes: number[] = []; - const objectsOld = deepClone( - this.lwm2mDeviceProfileFormGroup.get('observeAttrTelemetry').value.clientLwM2M) as ObjectLwM2M[]; - let isIdIndex = (element) => element.id === pathParameter[0]; + const objectsOld = this.lwm2mDeviceProfileFormGroup.get('observeAttrTelemetry').value.clientLwM2M as ObjectLwM2M[]; + let isIdIndex = (element) => element.id === objectId; const objIndex = objectsOld.findIndex(isIdIndex); if (objIndex >= 0) { pathParameterIndexes.push(objIndex); - isIdIndex = (element) => element.id === pathParameter[1]; + isIdIndex = (element) => element.id === instanceId; const instIndex = objectsOld[objIndex].instances.findIndex(isIdIndex); if (instIndex >= 0) { pathParameterIndexes.push(instIndex); - isIdIndex = (element) => element.id === pathParameter[2]; + isIdIndex = (element) => element.id === resourceId; const resIndex = objectsOld[objIndex].instances[instIndex].resources.findIndex(isIdIndex); if (resIndex >= 0) { pathParameterIndexes.push(resIndex); @@ -456,16 +426,16 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro if (index >= 0) { objectsOld.splice(index, 1); } - this.updateObserveAttrTelemetryObjectFormGroup(objectsOld); this.removeObserveAttrTelemetryFromJson(this.observe, value.id); this.removeObserveAttrTelemetryFromJson(this.telemetry, value.id); this.removeObserveAttrTelemetryFromJson(this.attribute, value.id); this.removeKeyNameFromJson(value.id); + this.updateObserveAttrTelemetryObjectFormGroup(objectsOld); this.upDateJsonAllConfig(); } private removeObserveAttrTelemetryFromJson = (observeAttrTel: string, id: number): void => { - const isIdIndex = (element: string) => element.startsWith(`/${id}`); + const isIdIndex = (element) => element.startsWith(`/${id}`); let index = this.configurationValue[this.observeAttr][observeAttrTel].findIndex(isIdIndex); while (index >= 0) { this.configurationValue[this.observeAttr][observeAttrTel].splice(index, 1); diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts index 625f9c77d9..3062c52ed3 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts @@ -19,18 +19,17 @@ import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Valida import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; -import { Observable, of } from 'rxjs'; -import { filter, map, mergeMap, tap } from 'rxjs/operators'; +import { Observable } from 'rxjs'; +import { filter, map, mergeMap, publishReplay, refCount, tap } from 'rxjs/operators'; import { ObjectLwM2M } from './profile-config.models'; import { TranslateService } from '@ngx-translate/core'; import { DeviceProfileService } from '@core/http/device-profile.service'; import { Direction } from '@shared/models/page/sort-order'; -import { isDefined, isDefinedAndNotNull, isEmptyStr } from '@core/utils'; +import { isDefined, isDefinedAndNotNull, isEmptyStr, isString } from '@core/utils'; @Component({ selector: 'tb-profile-lwm2m-object-list', templateUrl: './lwm2m-object-list.component.html', - styleUrls: [], providers: [ { provide: NG_VALUE_ACCESSOR, @@ -42,10 +41,10 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V private requiredValue: boolean; private dirty = false; - private allObjectsList: Observable>; + private lw2mModels: Observable>; + private modelValue: Array = []; lwm2mListFormGroup: FormGroup; - modelValue: Array | null; objectsList: Array = []; filteredObjectsList: Observable>; disabled = false; @@ -57,11 +56,8 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V @Input() set required(value: boolean) { - const newVal = coerceBooleanProperty(value); - if (this.requiredValue !== newVal) { - this.requiredValue = newVal; - this.updateValidators(); - } + this.requiredValue = coerceBooleanProperty(value); + this.updateValidators(); } @Output() @@ -73,7 +69,7 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V @ViewChild('objectInput') objectInput: ElementRef; private propagateChange = (v: any) => { - }; + } constructor(private store: Store, public translate: TranslateService, @@ -81,7 +77,7 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V private fb: FormBuilder) { this.lwm2mListFormGroup = this.fb.group({ objectsList: [this.objectsList], - objectLwm2m: [null, this.required ? [Validators.required] : []] + objectLwm2m: [''] }); } @@ -104,11 +100,10 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V if (value && typeof value !== 'string') { this.add(value); } else if (value === null) { - this.clear(this.objectInput.nativeElement.value); + this.clear(); } }), - filter((value) => typeof value === 'string'), - // map(value => value ? value : ''), + filter(searchText => isString(searchText)), mergeMap(searchText => this.fetchListObjects(searchText)) ); } @@ -127,23 +122,21 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V writeValue(value: any): void { this.searchText = ''; - const objectIds = 'objectIds'; - if (value.hasOwnProperty(objectIds) && value[objectIds] != null && value[objectIds].length > 0) { - this.modelValue = [...value[objectIds]]; - this.objectsList = value.objectsList; - } else { - this.objectsList = []; - this.modelValue = null; + if (isDefinedAndNotNull(value)) { + if (Array.isArray(value.objectIds)) { + this.modelValue = value.objectIds; + this.objectsList = value.objectsList; + } else { + this.objectsList = []; + this.modelValue = []; + } + this.lwm2mListFormGroup.get('objectsList').setValue(this.objectsList, {emitEvents: false}); + this.dirty = false; } - this.lwm2mListFormGroup.get('objectsList').setValue(this.objectsList); - this.dirty = true; } private add(object: ObjectLwM2M): void { - if (!this.modelValue || this.modelValue.indexOf(object.id) === -1) { - if (!this.modelValue) { - this.modelValue = []; - } + if (this.modelValue.indexOf(object.id) === -1) { this.modelValue.push(object.id); this.objectsList.push(object); this.lwm2mListFormGroup.get('objectsList').setValue(this.objectsList); @@ -176,41 +169,42 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V const filters = {names: [], ids: []}; if (isDefinedAndNotNull(searchText) && !isEmptyStr(searchText)) { const ids = searchText.match(/\d+/g); - filters.ids = isDefinedAndNotNull(ids) ? ids.map(Number) as [] : filters.ids; - const names = searchText.trim().split(" ") as []; - filters.names = names; + filters.ids = ids !== null ? ids.map(Number) : filters.ids; + filters.names = searchText.trim().toUpperCase().split(' '); } - const predicate = objectLwM2M => filters.names.filter(word => objectLwM2M.name.toUpperCase().includes(word.toUpperCase())).length>0 + const predicate = objectLwM2M => filters.names.find(word => objectLwM2M.name.toUpperCase().includes(word)) || filters.ids.includes(objectLwM2M.id); - return this.getListModels().pipe( + return this.getLwM2mModels().pipe( map(objectLwM2Ms => searchText ? objectLwM2Ms.filter(predicate) : objectLwM2Ms) ); } - private getListModels(): Observable> { - if (!this.allObjectsList) { + private getLwM2mModels(): Observable> { + if (!this.lw2mModels) { const sortOrder = { property: 'name', direction: Direction.ASC }; - this.allObjectsList = this.deviceProfileService.getLwm2mObjects(sortOrder, null, null).pipe( - mergeMap(objectsList => of(objectsList)) + this.lw2mModels = this.deviceProfileService.getLwm2mObjects(sortOrder).pipe( + publishReplay(1), + refCount() ); } - return this.allObjectsList; + return this.lw2mModels; } onFocus = (): void => { - if (this.dirty) { + if (!this.dirty) { this.lwm2mListFormGroup.get('objectLwm2m').updateValueAndValidity({onlySelf: true, emitEvent: true}); - this.dirty = false; + this.dirty = true; } } private clear = (value: string = ''): void => { this.objectInput.nativeElement.value = value; - this.lwm2mListFormGroup.get('objectLwm2m').patchValue(value, {emitEvent: true}); + this.searchText = ''; + this.lwm2mListFormGroup.get('objectLwm2m').patchValue(value); setTimeout(() => { this.objectInput.nativeElement.blur(); this.objectInput.nativeElement.focus(); diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.html index eb0e4bc88d..7b33264ba6 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.html @@ -16,23 +16,24 @@ --> -
+
- -
{{ objectLwM2M.get('name').value}} (object [{{ objectLwM2M.get('id').value}}])
- + + {{ objectLwM2M.get('name').value}} <id: {{ objectLwM2M.get('id').value}}> + + +
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts index 4eeeb4b3e5..b208ed7e14 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts @@ -176,7 +176,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor this.observeAttrTelemetryFormGroup.get('clientLwM2M').updateValueAndValidity(); } - trackByParams = (index: number): number => { + trackByParams = (index: number, element: any): number => { return index; } From 6cd6568ee3185af429c98daac416c1dfe616f62b Mon Sep 17 00:00:00 2001 From: ponvalavan annamalai Date: Tue, 26 Jan 2021 17:24:31 +0000 Subject: [PATCH 077/249] Dynamic color for data points --- .../components/widget/lib/maps/leaflet-map.ts | 6 +++++- .../components/widget/lib/maps/map-models.ts | 2 ++ .../components/widget/lib/maps/map-widget2.ts | 1 + .../home/components/widget/lib/maps/schemes.ts | 16 +++++++++++++++- .../trip-animation/trip-animation.component.ts | 4 ++++ 5 files changed, 27 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts index 57a0563a4e..ea3a24e0c5 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts @@ -628,8 +628,12 @@ export default abstract class LeafletMap { } for (const pointsList of pointsData) { pointsList.filter(pdata => !!this.convertPosition(pdata)).forEach(data => { + let pointColor = this.options.pointColor; + if (this.options.useColorPointFunction) { + pointColor = safeExecute(this.options.colorPointFunction,[data, pointsData, data.dsIndex]); + } const point = L.circleMarker(this.convertPosition(data), { - color: this.options.pointColor, + color: pointColor, radius: this.options.pointSize }); if (!this.options.pointTooltipOnRightPanel) { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts index 45830cbd55..664ba2ec6d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts @@ -201,6 +201,8 @@ export type TripAnimationSettings = { pointAsAnchorFunction: GenericFunction; tooltipFunction: GenericFunction; labelFunction: GenericFunction; + useColorPointFunction: boolean; + colorPointFunction: GenericFunction; }; export type actionsHandler = ($event: Event, datasource: Datasource) => void; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts index e1cad7a8f7..c543593db5 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts @@ -301,6 +301,7 @@ export class MapWidgetController implements MapWidgetInterface { labelFunction: parseFunction(settings.labelFunction, functionParams), tooltipFunction: parseFunction(settings.tooltipFunction, functionParams), colorFunction: parseFunction(settings.colorFunction, functionParams), + colorPointFunction: parseFunction(settings.colorPointFunction, functionParams), polygonColorFunction: parseFunction(settings.polygonColorFunction, functionParams), polygonTooltipFunction: parseFunction(settings.polygonTooltipFunction, functionParams), markerImageFunction: parseFunction(settings.markerImageFunction, ['data', 'images', 'dsData', 'dsIndex']), diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts index 9e1ce715ff..3c8b7f031c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts @@ -1036,6 +1036,15 @@ export const tripAnimationSchema = { title: 'Custom marker image', type: 'string' }, + useColorPointFunction: { + title: 'Use color point function', + type: 'boolean', + default: false + }, + colorPointFunction: { + title: 'Color point function: f(data, dsData, dsIndex)', + type: 'string' + }, markerImageSize: { title: 'Custom marker image size (px)', type: 'number', @@ -1081,7 +1090,12 @@ export const tripAnimationSchema = { }, 'useTooltipFunction', { key: 'tooltipFunction', type: 'javascript' - }, 'autocloseTooltip', { + }, 'autocloseTooltip', 'useColorPointFunction', + { + key: 'colorPointFunction', + type: 'javascript' + }, + { key: 'markerImage', type: 'image' }, 'markerImageSize', 'rotationAngle', 'useMarkerImageFunction', diff --git a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts index 9372e44655..ab616a144c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts @@ -112,6 +112,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy this.settings.pointAsAnchorFunction = parseFunction(this.settings.pointAsAnchorFunction, ['data', 'dsData', 'dsIndex']); this.settings.tooltipFunction = parseFunction(this.settings.tooltipFunction, ['data', 'dsData', 'dsIndex']); this.settings.labelFunction = parseFunction(this.settings.labelFunction, ['data', 'dsData', 'dsIndex']); + this.settings.colorPointFunction = parseFunction(this.settings.colorPointFunction, ['data', 'dsData', 'dsIndex']); this.normalizationStep = this.settings.normalizationStep; const subscription = this.ctx.defaultSubscription; subscription.callbacks.onDataUpdated = () => { @@ -180,6 +181,9 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy } if (this.settings.showPoints) { this.mapWidget.map.updatePoints(formattedInterpolatedTimeData.map(ds => _.union(ds)), this.calcTooltip); + } + if (this.settings.useColorPointFunction) { + this.mapWidget.map.updatePoints(_.values(_.union(this.interpolatedTimeData)[0]), this.calcTooltip); } this.mapWidget.map.updateMarkers(currentPosition, true, (trip) => { this.activeTrip = trip; From fc40047a5e1b20e1074b490276b7546cba161211 Mon Sep 17 00:00:00 2001 From: ponvalavan annamalai Date: Tue, 26 Jan 2021 18:01:55 +0000 Subject: [PATCH 078/249] Dynamic color for data points --- .../modules/home/components/widget/lib/maps/leaflet-map.ts | 4 ++-- .../modules/home/components/widget/lib/maps/map-models.ts | 2 +- .../modules/home/components/widget/lib/maps/map-widget2.ts | 2 +- .../widget/trip-animation/trip-animation.component.ts | 7 ++----- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts index ea3a24e0c5..d9f8b055c8 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts @@ -626,10 +626,10 @@ export default abstract class LeafletMap { } this.points = new FeatureGroup(); } + let pointColor = this.options.pointColor; for (const pointsList of pointsData) { pointsList.filter(pdata => !!this.convertPosition(pdata)).forEach(data => { - let pointColor = this.options.pointColor; - if (this.options.useColorPointFunction) { + if (this.options.useColorPointFunction) { pointColor = safeExecute(this.options.colorPointFunction,[data, pointsData, data.dsIndex]); } const point = L.circleMarker(this.convertPosition(data), { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts index 664ba2ec6d..d5c7be4497 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts @@ -201,7 +201,7 @@ export type TripAnimationSettings = { pointAsAnchorFunction: GenericFunction; tooltipFunction: GenericFunction; labelFunction: GenericFunction; - useColorPointFunction: boolean; + useColorPointFunction: boolean; colorPointFunction: GenericFunction; }; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts index c543593db5..ed83323d6c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts @@ -301,7 +301,7 @@ export class MapWidgetController implements MapWidgetInterface { labelFunction: parseFunction(settings.labelFunction, functionParams), tooltipFunction: parseFunction(settings.tooltipFunction, functionParams), colorFunction: parseFunction(settings.colorFunction, functionParams), - colorPointFunction: parseFunction(settings.colorPointFunction, functionParams), + colorPointFunction: parseFunction(settings.colorPointFunction, functionParams), polygonColorFunction: parseFunction(settings.polygonColorFunction, functionParams), polygonTooltipFunction: parseFunction(settings.polygonTooltipFunction, functionParams), markerImageFunction: parseFunction(settings.markerImageFunction, ['data', 'images', 'dsData', 'dsIndex']), diff --git a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts index ab616a144c..319a1139ed 100644 --- a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts @@ -112,7 +112,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy this.settings.pointAsAnchorFunction = parseFunction(this.settings.pointAsAnchorFunction, ['data', 'dsData', 'dsIndex']); this.settings.tooltipFunction = parseFunction(this.settings.tooltipFunction, ['data', 'dsData', 'dsIndex']); this.settings.labelFunction = parseFunction(this.settings.labelFunction, ['data', 'dsData', 'dsIndex']); - this.settings.colorPointFunction = parseFunction(this.settings.colorPointFunction, ['data', 'dsData', 'dsIndex']); + this.settings.colorPointFunction = parseFunction(this.settings.colorPointFunction, ['data', 'dsData', 'dsIndex']); this.normalizationStep = this.settings.normalizationStep; const subscription = this.ctx.defaultSubscription; subscription.callbacks.onDataUpdated = () => { @@ -179,11 +179,8 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy if (this.settings.showPolygon) { this.mapWidget.map.updatePolygons(this.interpolatedTimeData); } - if (this.settings.showPoints) { + if (this.settings.showPoints || this.settings.useColorPointFunction) { this.mapWidget.map.updatePoints(formattedInterpolatedTimeData.map(ds => _.union(ds)), this.calcTooltip); - } - if (this.settings.useColorPointFunction) { - this.mapWidget.map.updatePoints(_.values(_.union(this.interpolatedTimeData)[0]), this.calcTooltip); } this.mapWidget.map.updateMarkers(currentPosition, true, (trip) => { this.activeTrip = trip; From 0219b8a6fd70bff427ea446687d5327633bb51d6 Mon Sep 17 00:00:00 2001 From: ponvalavan annamalai Date: Tue, 26 Jan 2021 18:12:21 +0000 Subject: [PATCH 079/249] Dynamic color for data points --- .../app/modules/home/components/widget/lib/maps/leaflet-map.ts | 2 +- .../app/modules/home/components/widget/lib/maps/map-models.ts | 2 +- .../app/modules/home/components/widget/lib/maps/map-widget2.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts index d9f8b055c8..67f44cd941 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts @@ -626,7 +626,7 @@ export default abstract class LeafletMap { } this.points = new FeatureGroup(); } - let pointColor = this.options.pointColor; + let pointColor = this.options.pointColor; for (const pointsList of pointsData) { pointsList.filter(pdata => !!this.convertPosition(pdata)).forEach(data => { if (this.options.useColorPointFunction) { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts index d5c7be4497..664ba2ec6d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts @@ -201,7 +201,7 @@ export type TripAnimationSettings = { pointAsAnchorFunction: GenericFunction; tooltipFunction: GenericFunction; labelFunction: GenericFunction; - useColorPointFunction: boolean; + useColorPointFunction: boolean; colorPointFunction: GenericFunction; }; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts index ed83323d6c..393ea747a0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts @@ -301,7 +301,7 @@ export class MapWidgetController implements MapWidgetInterface { labelFunction: parseFunction(settings.labelFunction, functionParams), tooltipFunction: parseFunction(settings.tooltipFunction, functionParams), colorFunction: parseFunction(settings.colorFunction, functionParams), - colorPointFunction: parseFunction(settings.colorPointFunction, functionParams), + colorPointFunction: parseFunction(settings.colorPointFunction, functionParams), polygonColorFunction: parseFunction(settings.polygonColorFunction, functionParams), polygonTooltipFunction: parseFunction(settings.polygonTooltipFunction, functionParams), markerImageFunction: parseFunction(settings.markerImageFunction, ['data', 'images', 'dsData', 'dsIndex']), From 68eebaf04120b07397535a47ba21bdc728578fad Mon Sep 17 00:00:00 2001 From: ponvalavan annamalai Date: Tue, 26 Jan 2021 18:15:00 +0000 Subject: [PATCH 080/249] removed spaces -dynamic color for data points --- .../app/modules/home/components/widget/lib/maps/map-models.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts index 664ba2ec6d..cbf5883659 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts @@ -201,7 +201,7 @@ export type TripAnimationSettings = { pointAsAnchorFunction: GenericFunction; tooltipFunction: GenericFunction; labelFunction: GenericFunction; - useColorPointFunction: boolean; + useColorPointFunction: boolean; colorPointFunction: GenericFunction; }; From 5f3cf1e3a2a77a13cde03d3309540824d43cf059 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 26 Jan 2021 22:10:26 +0200 Subject: [PATCH 081/249] Lwm2m: front: update filter for keyName --- .../server/LwM2MTransportServiceImpl.java | 2 +- .../lwm2m/server/client/LwM2MClient.java | 4 +- ...ofile-transport-configuration.component.ts | 52 ++++--------------- 3 files changed, 14 insertions(+), 44 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServiceImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServiceImpl.java index 3255d24760..10df996b79 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServiceImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServiceImpl.java @@ -154,7 +154,7 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { lwM2MClient.setLwM2MTransportServiceImpl(this); lwM2MClient.setSessionUuid(UUID.randomUUID()); this.sentLogsToThingsboard(LOG_LW2M_INFO + ": Client Registered", registration); -// this.setLwM2mFromClientValue(lwServer, registration, lwM2MClient); + this.setLwM2mFromClientValue(lwServer, registration, lwM2MClient); SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration); if (sessionInfo != null) { lwM2MClient.setDeviceUuid(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB())); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java index f20853299d..3c1a886454 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java @@ -93,7 +93,7 @@ public class LwM2MClient implements Cloneable { this.pendingRequests.remove(path); if (this.pendingRequests.size() == 0) { this.initValue(); -// this.lwM2MTransportServiceImpl.putDelayedUpdateResourcesThingsboard(this); + this.lwM2MTransportServiceImpl.putDelayedUpdateResourcesThingsboard(this); } } @@ -106,7 +106,7 @@ public class LwM2MClient implements Cloneable { ((LwM2mObjectInstance)((ReadResponse)resp).getContent()).getResources().forEach((k, v) -> { String rez = pathIds.toString() + "/" + k; if (((LwM2mObjectInstance) ((ReadResponse) resp).getContent()).getResource(k) instanceof LwM2mMultipleResource){ -// this.resources.put(rez, new ResourceValue(v.getInstances().values(), null, true)); + this.resources.put(rez, new ResourceValue(v.getValues(), null, true)); } else { this.resources.put(rez, new ResourceValue(null, v.getValue(), false)); diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts index e9b6b17edc..6451bbb0b8 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts @@ -271,6 +271,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro const observeArray: Array = []; const attributeArray: Array = []; const telemetryArray: Array = []; + const keyNameNew = {}; const observeJson: ObjectLwM2M[] = JSON.parse(JSON.stringify(val)); const paths = new Set(); let pathObj; @@ -293,18 +294,22 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro const resourcesJson = instanceValue as ResourceLwM2M[]; if (resourcesJson.length > 0) { resourcesJson.forEach(res => { - for (const [resourceKey, idResource] of Object.entries(res)) { + for (const [resourceKey, value] of Object.entries(res)) { if (resourceKey === 'id') { - pathRes = `/${pathObj}/${pathInst}/${idResource}`; - } else if (resourceKey === 'observe' && idResource) { + pathRes = `/${pathObj}/${pathInst}/${value}`; + } else if (resourceKey === 'observe' && value) { observeArray.push(pathRes); - } else if (resourceKey === 'attribute' && idResource) { + } else if (resourceKey === 'attribute' && value) { attributeArray.push(pathRes); paths.add(pathRes); - } else if (resourceKey === 'telemetry' && idResource) { + } else if (resourceKey === 'telemetry' && value) { telemetryArray.push(pathRes); paths.add(pathRes); } + else if (resourceKey === this.keyName && paths.has(pathRes)) { + console.warn(pathRes, value); + keyNameNew[pathRes] = value; + } } }); } @@ -326,7 +331,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro this.configurationValue[this.observeAttr][this.attribute] = attributeArray; this.configurationValue[this.observeAttr][this.telemetry] = telemetryArray; } - this.updateKeyName(paths); + this.configurationValue[this.observeAttr][this.keyName] = this.sortObjectKeyPathJson('keyName', keyNameNew); } sortObjectKeyPathJson = (key: string, value: object): object => { @@ -352,41 +357,6 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro }); } - private updateKeyName = (paths: Set): void => { - const keyNameNew = {}; - paths.forEach(path => { - const pathParameter = this.findIndexesForIds(path); - if (pathParameter.length === 3) { - keyNameNew[path] = this.lwm2mDeviceProfileFormGroup.get('observeAttrTelemetry').value - .clientLwM2M[pathParameter[0]].instances[pathParameter[1]].resources[pathParameter[2]][this.keyName]; - } - }); - this.configurationValue[this.observeAttr][this.keyName] = this.sortObjectKeyPathJson('keyName', keyNameNew); - } - - private findIndexesForIds = (path: string): number[] => { - const [objectId, instanceId, resourceId] = Array.from(path.substring(1).split('/'), Number); - // TODO: All paths to map - const pathParameterIndexes: number[] = []; - const objectsOld = this.lwm2mDeviceProfileFormGroup.get('observeAttrTelemetry').value.clientLwM2M as ObjectLwM2M[]; - let isIdIndex = (element) => element.id === objectId; - const objIndex = objectsOld.findIndex(isIdIndex); - if (objIndex >= 0) { - pathParameterIndexes.push(objIndex); - isIdIndex = (element) => element.id === instanceId; - const instIndex = objectsOld[objIndex].instances.findIndex(isIdIndex); - if (instIndex >= 0) { - pathParameterIndexes.push(instIndex); - isIdIndex = (element) => element.id === resourceId; - const resIndex = objectsOld[objIndex].instances[instIndex].resources.findIndex(isIdIndex); - if (resIndex >= 0) { - pathParameterIndexes.push(resIndex); - } - } - } - return pathParameterIndexes; - } - private getObjectsFromJsonAllConfig = (): number[] => { const objectsIds = new Set(); if (this.configurationValue[this.observeAttr]) { From 581bb536f5e2281981815e338d48f05e41bb2592 Mon Sep 17 00:00:00 2001 From: AndrewVolostnykhThingsboard Date: Wed, 27 Jan 2021 12:00:20 +0200 Subject: [PATCH 082/249] findHighestAlarmStatus: fixed using Repository Query --- .../server/dao/alarm/BaseAlarmService.java | 66 +++++++++++-------- .../server/dao/sql/alarm/AlarmRepository.java | 9 +++ .../dao/service/BaseAlarmServiceTest.java | 56 ++++++++++++++++ 3 files changed, 102 insertions(+), 29 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java index 0c781478d5..ad9bc22e01 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java @@ -28,26 +28,43 @@ import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.common.data.Tenant; -import org.thingsboard.server.common.data.alarm.*; +import org.thingsboard.server.common.data.alarm.Alarm; +import org.thingsboard.server.common.data.alarm.AlarmInfo; +import org.thingsboard.server.common.data.alarm.AlarmQuery; +import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; +import org.thingsboard.server.common.data.alarm.AlarmSeverity; +import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; -import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.query.AlarmData; +import org.thingsboard.server.common.data.query.AlarmDataPageLink; import org.thingsboard.server.common.data.query.AlarmDataQuery; -import org.thingsboard.server.common.data.relation.*; +import org.thingsboard.server.common.data.query.DeviceTypeFilter; +import org.thingsboard.server.common.data.relation.EntityRelation; +import org.thingsboard.server.common.data.relation.EntityRelationsQuery; +import org.thingsboard.server.common.data.relation.EntitySearchDirection; +import org.thingsboard.server.common.data.relation.RelationTypeGroup; +import org.thingsboard.server.common.data.relation.RelationsSearchParameters; import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.DataValidator; +import org.thingsboard.server.dao.sql.alarm.AlarmRepository; import org.thingsboard.server.dao.tenant.TenantDao; import javax.annotation.Nullable; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -72,6 +89,9 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ @Autowired private EntityService entityService; + @Autowired + private AlarmRepository alarmRepository; + protected ExecutorService readResultsProcessingExecutor; @PostConstruct @@ -300,35 +320,23 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ @Override public AlarmSeverity findHighestAlarmSeverity(TenantId tenantId, EntityId entityId, AlarmSearchStatus alarmSearchStatus, AlarmStatus alarmStatus) { - TimePageLink nextPageLink = new TimePageLink(100); - boolean hasNext = true; - AlarmSeverity highestSeverity = null; - AlarmQuery query; - while (hasNext && AlarmSeverity.CRITICAL != highestSeverity) { - query = new AlarmQuery(entityId, nextPageLink, alarmSearchStatus, alarmStatus, false, null); - PageData alarms = alarmDao.findAlarms(tenantId, query); - - if (alarms.hasNext()) { - nextPageLink = nextPageLink.nextPageLink(); - } else { - hasNext = false; - } + Set statusList = null; + if (alarmSearchStatus != null) { + statusList = alarmSearchStatus.getStatuses(); + } else if (alarmStatus != null) { + statusList = Collections.singleton(alarmStatus); + } - AlarmSeverity severity = detectHighestSeverity(alarms.getData()); - if (severity == null) { - continue; - } + List alarmSeverities = alarmRepository.findHighestAlarmSeverity(tenantId.getId(), entityId.getId(), statusList); - if (severity == AlarmSeverity.CRITICAL || highestSeverity == null) { - highestSeverity = severity; - } else { - highestSeverity = highestSeverity.compareTo(severity) < 0 ? highestSeverity : severity; - } - } - return highestSeverity; + return alarmSeverities.stream().min(AlarmSeverity::compareTo).orElse(null); + } + + private AlarmDataQuery toQuery(AlarmDataPageLink pageLink) { + return new AlarmDataQuery(new DeviceTypeFilter(), pageLink, null, null, null, Collections.EMPTY_LIST); } - private AlarmSeverity detectHighestSeverity(List alarms) { + private AlarmSeverity detectHighestSeverity(List alarms) { if (!alarms.isEmpty()) { List sorted = new ArrayList(alarms); sorted.sort(Comparator.comparing(Alarm::getSeverity)); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java index f3206f30de..df9c033579 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java @@ -20,6 +20,7 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.query.Param; +import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.dao.model.sql.AlarmEntity; import org.thingsboard.server.dao.model.sql.AlarmInfoEntity; @@ -75,4 +76,12 @@ public interface AlarmRepository extends CrudRepository { @Param("searchText") String searchText, Pageable pageable); + @Query("SELECT alarm.severity FROM AlarmEntity alarm" + + " WHERE alarm.tenantId = :tenantId" + + " AND alarm.originatorId = :entityId" + + " AND ((:status) IS NULL OR alarm.status in (:status))") + List findHighestAlarmSeverity(@Param("tenantId") UUID tenantId, + @Param("entityId") UUID entityId, + @Param("status") Set status); + } diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java index 3536b6066f..a53469ddf4 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java @@ -354,6 +354,62 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { return new AlarmDataQuery(new DeviceTypeFilter(), pageLink, null, null, null, alarmFields); } + @Test + public void testFindHighestAlarmSeverity() throws ExecutionException, InterruptedException { + Customer customer = new Customer(); + customer.setTitle("TestCustomer"); + customer.setTenantId(tenantId); + customer = customerService.saveCustomer(customer); + + Device customerDevice = new Device(); + customerDevice.setName("TestCustomerDevice"); + customerDevice.setType("default"); + customerDevice.setTenantId(tenantId); + customerDevice.setCustomerId(customer.getId()); + customerDevice = deviceService.saveDevice(customerDevice); + + long ts = System.currentTimeMillis(); + Alarm alarm1 = Alarm.builder() + .tenantId(tenantId) + .originator(customerDevice.getId()) + .type(TEST_ALARM) + .severity(AlarmSeverity.MAJOR) + .status(AlarmStatus.ACTIVE_UNACK) + .startTs(ts) + .build(); + alarm1 = alarmService.createOrUpdateAlarm(alarm1).getAlarm(); + alarmService.clearAlarm(tenantId, alarm1.getId(), null, System.currentTimeMillis()).get(); + + ts = System.currentTimeMillis(); + Alarm alarm2 = Alarm.builder() + .tenantId(tenantId) + .originator(customerDevice.getId()) + .type(TEST_ALARM) + .severity(AlarmSeverity.MINOR) + .status(AlarmStatus.ACTIVE_ACK) + .startTs(ts) + .build(); + alarm2 = alarmService.createOrUpdateAlarm(alarm2).getAlarm(); + alarmService.clearAlarm(tenantId, alarm2.getId(), null, System.currentTimeMillis()).get(); + + ts = System.currentTimeMillis(); + Alarm alarm3 = Alarm.builder() + .tenantId(tenantId) + .originator(customerDevice.getId()) + .type(TEST_ALARM) + .severity(AlarmSeverity.CRITICAL) + .status(AlarmStatus.ACTIVE_ACK) + .startTs(ts) + .build(); + alarm3 = alarmService.createOrUpdateAlarm(alarm3).getAlarm(); + + Assert.assertEquals(AlarmSeverity.MAJOR, alarmService.findHighestAlarmSeverity(tenantId, customerDevice.getId(), AlarmSearchStatus.UNACK, null)); + Assert.assertEquals(AlarmSeverity.CRITICAL, alarmService.findHighestAlarmSeverity(tenantId, customerDevice.getId(), null, null)); + Assert.assertEquals(AlarmSeverity.MAJOR, alarmService.findHighestAlarmSeverity(tenantId, customerDevice.getId(), null, AlarmStatus.CLEARED_UNACK)); + Assert.assertEquals(AlarmSeverity.CRITICAL, alarmService.findHighestAlarmSeverity(tenantId, customerDevice.getId(), AlarmSearchStatus.ACTIVE, null)); + Assert.assertEquals(AlarmSeverity.MINOR, alarmService.findHighestAlarmSeverity(tenantId, customerDevice.getId(), null, AlarmStatus.CLEARED_ACK)); + } + @Test public void testFindAlarmUsingAlarmDataQuery() throws ExecutionException, InterruptedException { AssetId parentId = new AssetId(Uuids.timeBased()); From beeade8b07fab33cba37e458da49d2223c4e3257 Mon Sep 17 00:00:00 2001 From: AndrewVolostnykhThingsboard Date: Wed, 27 Jan 2021 12:16:43 +0200 Subject: [PATCH 083/249] findHighestAlarmStatus: code cleaning --- .../thingsboard/server/dao/alarm/AlarmDao.java | 6 +++++- .../server/dao/alarm/BaseAlarmService.java | 17 +---------------- .../server/dao/sql/alarm/AlarmRepository.java | 2 +- .../server/dao/sql/alarm/JpaAlarmDao.java | 6 ++++++ .../dao/service/BaseAlarmServiceTest.java | 9 +++------ 5 files changed, 16 insertions(+), 24 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java index 6c12b5f753..ebbfae0f05 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java @@ -19,16 +19,18 @@ import com.google.common.util.concurrent.ListenableFuture; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.alarm.AlarmQuery; +import org.thingsboard.server.common.data.alarm.AlarmSeverity; +import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.query.AlarmData; -import org.thingsboard.server.common.data.query.AlarmDataPageLink; import org.thingsboard.server.common.data.query.AlarmDataQuery; import org.thingsboard.server.dao.Dao; import java.util.Collection; +import java.util.Set; import java.util.UUID; /** @@ -48,4 +50,6 @@ public interface AlarmDao extends Dao { PageData findAlarmDataByQueryForEntities(TenantId tenantId, CustomerId customerId, AlarmDataQuery query, Collection orderedEntityIds); + + Set findAlarmSeverities(TenantId tenantId, EntityId entityId, Set status); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java index ad9bc22e01..4c16d18ed1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java @@ -52,7 +52,6 @@ import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.DataValidator; -import org.thingsboard.server.dao.sql.alarm.AlarmRepository; import org.thingsboard.server.dao.tenant.TenantDao; import javax.annotation.Nullable; @@ -61,7 +60,6 @@ import javax.annotation.PreDestroy; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.Comparator; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; @@ -89,9 +87,6 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ @Autowired private EntityService entityService; - @Autowired - private AlarmRepository alarmRepository; - protected ExecutorService readResultsProcessingExecutor; @PostConstruct @@ -327,7 +322,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ statusList = Collections.singleton(alarmStatus); } - List alarmSeverities = alarmRepository.findHighestAlarmSeverity(tenantId.getId(), entityId.getId(), statusList); + Set alarmSeverities = alarmDao.findAlarmSeverities(tenantId, entityId, statusList); return alarmSeverities.stream().min(AlarmSeverity::compareTo).orElse(null); } @@ -336,16 +331,6 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ return new AlarmDataQuery(new DeviceTypeFilter(), pageLink, null, null, null, Collections.EMPTY_LIST); } - private AlarmSeverity detectHighestSeverity(List alarms) { - if (!alarms.isEmpty()) { - List sorted = new ArrayList(alarms); - sorted.sort(Comparator.comparing(Alarm::getSeverity)); - return sorted.get(0).getSeverity(); - } else { - return null; - } - } - private void deleteRelation(TenantId tenantId, EntityRelation alarmRelation) { log.debug("Deleting Alarm relation: {}", alarmRelation); relationService.deleteRelation(tenantId, alarmRelation); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java index df9c033579..0a39802915 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java @@ -80,7 +80,7 @@ public interface AlarmRepository extends CrudRepository { " WHERE alarm.tenantId = :tenantId" + " AND alarm.originatorId = :entityId" + " AND ((:status) IS NULL OR alarm.status in (:status))") - List findHighestAlarmSeverity(@Param("tenantId") UUID tenantId, + Set findAlarmSeverities(@Param("tenantId") UUID tenantId, @Param("entityId") UUID entityId, @Param("status") Set status); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java index d74092ac95..722928e1b8 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java @@ -24,6 +24,7 @@ import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.alarm.AlarmQuery; +import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; @@ -120,4 +121,9 @@ public class JpaAlarmDao extends JpaAbstractDao implements A public PageData findAlarmDataByQueryForEntities(TenantId tenantId, CustomerId customerId, AlarmDataQuery query, Collection orderedEntityIds) { return alarmQueryRepository.findAlarmDataByQueryForEntities(tenantId, customerId, query, orderedEntityIds); } + + @Override + public Set findAlarmSeverities(TenantId tenantId, EntityId entityId, Set status) { + return alarmRepository.findAlarmSeverities(tenantId.getId(), entityId.getId(), status); + } } diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java index a53469ddf4..9d20aa5799 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java @@ -368,38 +368,35 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { customerDevice.setCustomerId(customer.getId()); customerDevice = deviceService.saveDevice(customerDevice); - long ts = System.currentTimeMillis(); Alarm alarm1 = Alarm.builder() .tenantId(tenantId) .originator(customerDevice.getId()) .type(TEST_ALARM) .severity(AlarmSeverity.MAJOR) .status(AlarmStatus.ACTIVE_UNACK) - .startTs(ts) + .startTs(System.currentTimeMillis()) .build(); alarm1 = alarmService.createOrUpdateAlarm(alarm1).getAlarm(); alarmService.clearAlarm(tenantId, alarm1.getId(), null, System.currentTimeMillis()).get(); - ts = System.currentTimeMillis(); Alarm alarm2 = Alarm.builder() .tenantId(tenantId) .originator(customerDevice.getId()) .type(TEST_ALARM) .severity(AlarmSeverity.MINOR) .status(AlarmStatus.ACTIVE_ACK) - .startTs(ts) + .startTs(System.currentTimeMillis()) .build(); alarm2 = alarmService.createOrUpdateAlarm(alarm2).getAlarm(); alarmService.clearAlarm(tenantId, alarm2.getId(), null, System.currentTimeMillis()).get(); - ts = System.currentTimeMillis(); Alarm alarm3 = Alarm.builder() .tenantId(tenantId) .originator(customerDevice.getId()) .type(TEST_ALARM) .severity(AlarmSeverity.CRITICAL) .status(AlarmStatus.ACTIVE_ACK) - .startTs(ts) + .startTs(System.currentTimeMillis()) .build(); alarm3 = alarmService.createOrUpdateAlarm(alarm3).getAlarm(); From f54dc932f7cc674b2f5b536abd2df1ca70cb9bd9 Mon Sep 17 00:00:00 2001 From: AndrewVolostnykhThingsboard Date: Wed, 27 Jan 2021 12:22:36 +0200 Subject: [PATCH 084/249] findHighestAlarmStatus: test for no alarm created, code cleaning --- .../org/thingsboard/server/dao/sql/alarm/AlarmRepository.java | 4 ++-- .../thingsboard/server/dao/service/BaseAlarmServiceTest.java | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java index 0a39802915..f34048c5ad 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java @@ -81,7 +81,7 @@ public interface AlarmRepository extends CrudRepository { " AND alarm.originatorId = :entityId" + " AND ((:status) IS NULL OR alarm.status in (:status))") Set findAlarmSeverities(@Param("tenantId") UUID tenantId, - @Param("entityId") UUID entityId, - @Param("status") Set status); + @Param("entityId") UUID entityId, + @Param("status") Set status); } diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java index 9d20aa5799..a885ac38de 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java @@ -368,6 +368,9 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { customerDevice.setCustomerId(customer.getId()); customerDevice = deviceService.saveDevice(customerDevice); + // no one alarms was created + Assert.assertNull(alarmService.findHighestAlarmSeverity(tenantId, customerDevice.getId(), null, null)); + Alarm alarm1 = Alarm.builder() .tenantId(tenantId) .originator(customerDevice.getId()) From 82ae2eb36fc49568bc88628dd0d59ea9589e93cb Mon Sep 17 00:00:00 2001 From: AndrewVolostnykhThingsboard Date: Wed, 27 Jan 2021 12:25:29 +0200 Subject: [PATCH 085/249] findHighestAlarmStatus: code cleaning (i believe that last) --- .../org/thingsboard/server/dao/alarm/BaseAlarmService.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java index 4c16d18ed1..b239b8e9f8 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java @@ -327,10 +327,6 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ return alarmSeverities.stream().min(AlarmSeverity::compareTo).orElse(null); } - private AlarmDataQuery toQuery(AlarmDataPageLink pageLink) { - return new AlarmDataQuery(new DeviceTypeFilter(), pageLink, null, null, null, Collections.EMPTY_LIST); - } - private void deleteRelation(TenantId tenantId, EntityRelation alarmRelation) { log.debug("Deleting Alarm relation: {}", alarmRelation); relationService.deleteRelation(tenantId, alarmRelation); From 5ce512b853bb35feffab0b7f427932605e004236 Mon Sep 17 00:00:00 2001 From: AndrewVolostnykhThingsboard Date: Wed, 27 Jan 2021 12:34:57 +0200 Subject: [PATCH 086/249] rest-client: getDeviceTypes fixed --- .../src/main/java/org/thingsboard/rest/client/RestClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java b/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java index 151edf9e8f..39fd5c1db1 100644 --- a/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java +++ b/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java @@ -1170,7 +1170,7 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable { public List getDeviceTypes() { return restTemplate.exchange( - baseURL + "/api/devices", + baseURL + "/api/device/types", HttpMethod.GET, HttpEntity.EMPTY, new ParameterizedTypeReference>() { From 2b47fe92029f0baef26c150caa4d5e8cb15f7d9f Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Wed, 27 Jan 2021 13:38:12 +0200 Subject: [PATCH 087/249] Updated license header --- .../controller/DeviceLwm2mController.java | 2 +- .../service/lwm2m/LwM2MModelsRepository.java | 2 +- .../server/common/data/lwm2m/LwM2mInstance.java | 2 +- .../server/common/data/lwm2m/LwM2mObject.java | 2 +- .../server/common/data/lwm2m/LwM2mResource.java | 2 +- .../common/data/lwm2m/ServerSecurityConfig.java | 2 +- common/transport/lwm2m/pom.xml | 17 +++++++++++++++++ ...2MTransportBootstrapServerConfiguration.java | 2 +- ...wM2MTransportBootstrapServerInitializer.java | 2 +- .../LwM2MTransportContextBootstrap.java | 2 +- .../bootstrap/secure/LwM2MBootstrapConfig.java | 2 +- .../secure/LwM2MBootstrapSecurityStore.java | 2 +- .../bootstrap/secure/LwM2MBootstrapServers.java | 2 +- .../LwM2MInMemoryBootstrapConfigStore.java | 2 +- .../bootstrap/secure/LwM2MServerBootstrap.java | 2 +- .../LwM2mDefaultBootstrapSessionManager.java | 2 +- .../lwm2m/secure/LWM2MGenerationPSkRPkECC.java | 2 +- .../lwm2m/secure/LwM2MSecurityMode.java | 2 +- .../LwM2mCredentialsSecurityInfoValidator.java | 2 +- .../lwm2m/secure/LwM2mRPkCredentials.java | 2 +- .../lwm2m/secure/ReadResultSecurityStore.java | 2 +- .../lwm2m/server/LwM2MSessionMsgListener.java | 2 +- .../server/LwM2MTransportContextServer.java | 2 +- .../lwm2m/server/LwM2MTransportHandler.java | 2 +- .../lwm2m/server/LwM2MTransportRequest.java | 2 +- .../LwM2MTransportServerConfiguration.java | 2 +- .../server/LwM2MTransportServerInitializer.java | 2 +- .../lwm2m/server/LwM2MTransportService.java | 2 +- .../lwm2m/server/LwM2MTransportServiceImpl.java | 2 +- .../lwm2m/server/LwM2mServerListener.java | 2 +- .../lwm2m/server/adaptors/LwM2MJsonAdaptor.java | 2 +- .../server/adaptors/LwM2MTransportAdaptor.java | 2 +- .../client/AttrTelemetryObserveValue.java | 2 +- .../lwm2m/server/client/LwM2MClient.java | 2 +- .../lwm2m/server/client/ModelObject.java | 2 +- .../lwm2m/server/client/ResourceValue.java | 2 +- .../client/ResultsAnalyzerParameters.java | 2 +- .../secure/LwM2mInMemorySecurityStore.java | 2 +- .../lwm2m/utils/LwM2mValueConverterImpl.java | 2 +- .../transport/lwm2m/utils/TypeServer.java | 2 +- .../credentials/shell/lwM2M_credentials.sh | 2 +- .../lwm2m/LwM2MTransportConfigBootstrap.java | 2 +- .../lwm2m/LwM2MTransportConfigServer.java | 2 +- docker/tb-transports/lwm2m/conf/logback.xml | 2 +- .../lwm2m/conf/tb-lwm2m-transport.conf | 2 +- msa/transport/lwm2m/docker/Dockerfile | 2 +- .../lwm2m/docker/start-tb-lwm2m-transport.sh | 2 +- msa/transport/lwm2m/pom.xml | 2 +- transport/lwm2m/pom.xml | 2 +- transport/lwm2m/src/main/conf/logback.xml | 2 +- .../lwm2m/src/main/conf/tb-lwm2m-transport.conf | 2 +- .../data/credentials/shell/lwM2M_credentials.sh | 2 +- transport/lwm2m/src/main/data/models/10241.xml | 2 +- transport/lwm2m/src/main/data/models/10242.xml | 2 +- transport/lwm2m/src/main/data/models/10243.xml | 2 +- transport/lwm2m/src/main/data/models/10244.xml | 2 +- transport/lwm2m/src/main/data/models/10245.xml | 2 +- transport/lwm2m/src/main/data/models/10246.xml | 2 +- transport/lwm2m/src/main/data/models/10247.xml | 2 +- transport/lwm2m/src/main/data/models/10248.xml | 2 +- transport/lwm2m/src/main/data/models/10249.xml | 2 +- transport/lwm2m/src/main/data/models/10250.xml | 2 +- transport/lwm2m/src/main/data/models/10251.xml | 2 +- transport/lwm2m/src/main/data/models/10252.xml | 2 +- transport/lwm2m/src/main/data/models/10253.xml | 2 +- transport/lwm2m/src/main/data/models/10254.xml | 2 +- transport/lwm2m/src/main/data/models/10255.xml | 2 +- transport/lwm2m/src/main/data/models/10256.xml | 2 +- transport/lwm2m/src/main/data/models/10257.xml | 2 +- transport/lwm2m/src/main/data/models/10258.xml | 2 +- transport/lwm2m/src/main/data/models/10259.xml | 2 +- .../lwm2m/src/main/data/models/10260-2_0.xml | 2 +- transport/lwm2m/src/main/data/models/10262.xml | 2 +- transport/lwm2m/src/main/data/models/10263.xml | 2 +- transport/lwm2m/src/main/data/models/10264.xml | 2 +- transport/lwm2m/src/main/data/models/10265.xml | 2 +- transport/lwm2m/src/main/data/models/10266.xml | 2 +- transport/lwm2m/src/main/data/models/10267.xml | 2 +- transport/lwm2m/src/main/data/models/10268.xml | 2 +- transport/lwm2m/src/main/data/models/10269.xml | 2 +- transport/lwm2m/src/main/data/models/10270.xml | 2 +- transport/lwm2m/src/main/data/models/10271.xml | 2 +- transport/lwm2m/src/main/data/models/10272.xml | 2 +- transport/lwm2m/src/main/data/models/10273.xml | 2 +- transport/lwm2m/src/main/data/models/10274.xml | 2 +- transport/lwm2m/src/main/data/models/10275.xml | 2 +- transport/lwm2m/src/main/data/models/10276.xml | 2 +- transport/lwm2m/src/main/data/models/10277.xml | 2 +- transport/lwm2m/src/main/data/models/10278.xml | 2 +- transport/lwm2m/src/main/data/models/10279.xml | 2 +- transport/lwm2m/src/main/data/models/10280.xml | 2 +- transport/lwm2m/src/main/data/models/10281.xml | 2 +- transport/lwm2m/src/main/data/models/10282.xml | 2 +- transport/lwm2m/src/main/data/models/10283.xml | 2 +- transport/lwm2m/src/main/data/models/10284.xml | 2 +- transport/lwm2m/src/main/data/models/10286.xml | 2 +- transport/lwm2m/src/main/data/models/10290.xml | 2 +- transport/lwm2m/src/main/data/models/10291.xml | 2 +- transport/lwm2m/src/main/data/models/10292.xml | 2 +- transport/lwm2m/src/main/data/models/10299.xml | 2 +- transport/lwm2m/src/main/data/models/10300.xml | 2 +- .../lwm2m/src/main/data/models/10308-2_0.xml | 2 +- transport/lwm2m/src/main/data/models/10309.xml | 2 +- transport/lwm2m/src/main/data/models/10311.xml | 2 +- transport/lwm2m/src/main/data/models/10313.xml | 2 +- transport/lwm2m/src/main/data/models/10314.xml | 2 +- transport/lwm2m/src/main/data/models/10315.xml | 2 +- transport/lwm2m/src/main/data/models/10316.xml | 2 +- transport/lwm2m/src/main/data/models/10318.xml | 2 +- transport/lwm2m/src/main/data/models/10319.xml | 2 +- transport/lwm2m/src/main/data/models/10320.xml | 2 +- transport/lwm2m/src/main/data/models/10322.xml | 2 +- transport/lwm2m/src/main/data/models/10323.xml | 2 +- transport/lwm2m/src/main/data/models/10324.xml | 2 +- transport/lwm2m/src/main/data/models/10326.xml | 2 +- transport/lwm2m/src/main/data/models/10327.xml | 2 +- transport/lwm2m/src/main/data/models/10328.xml | 2 +- transport/lwm2m/src/main/data/models/10329.xml | 2 +- transport/lwm2m/src/main/data/models/10330.xml | 2 +- transport/lwm2m/src/main/data/models/10331.xml | 2 +- transport/lwm2m/src/main/data/models/10332.xml | 2 +- transport/lwm2m/src/main/data/models/10333.xml | 2 +- transport/lwm2m/src/main/data/models/10334.xml | 2 +- transport/lwm2m/src/main/data/models/10335.xml | 2 +- transport/lwm2m/src/main/data/models/10336.xml | 2 +- transport/lwm2m/src/main/data/models/10337.xml | 2 +- transport/lwm2m/src/main/data/models/10338.xml | 2 +- transport/lwm2m/src/main/data/models/10339.xml | 2 +- transport/lwm2m/src/main/data/models/10340.xml | 2 +- transport/lwm2m/src/main/data/models/10341.xml | 2 +- transport/lwm2m/src/main/data/models/10342.xml | 2 +- transport/lwm2m/src/main/data/models/10343.xml | 2 +- transport/lwm2m/src/main/data/models/10344.xml | 2 +- transport/lwm2m/src/main/data/models/10345.xml | 2 +- transport/lwm2m/src/main/data/models/10346.xml | 2 +- transport/lwm2m/src/main/data/models/10347.xml | 2 +- transport/lwm2m/src/main/data/models/10348.xml | 2 +- transport/lwm2m/src/main/data/models/10349.xml | 2 +- transport/lwm2m/src/main/data/models/10350.xml | 2 +- transport/lwm2m/src/main/data/models/10351.xml | 2 +- transport/lwm2m/src/main/data/models/10352.xml | 2 +- transport/lwm2m/src/main/data/models/10353.xml | 2 +- transport/lwm2m/src/main/data/models/10354.xml | 2 +- transport/lwm2m/src/main/data/models/10355.xml | 2 +- transport/lwm2m/src/main/data/models/10356.xml | 2 +- transport/lwm2m/src/main/data/models/10357.xml | 2 +- transport/lwm2m/src/main/data/models/10358.xml | 2 +- transport/lwm2m/src/main/data/models/10359.xml | 2 +- transport/lwm2m/src/main/data/models/10360.xml | 2 +- transport/lwm2m/src/main/data/models/10361.xml | 2 +- transport/lwm2m/src/main/data/models/10362.xml | 2 +- transport/lwm2m/src/main/data/models/10363.xml | 2 +- transport/lwm2m/src/main/data/models/10364.xml | 2 +- transport/lwm2m/src/main/data/models/10365.xml | 2 +- transport/lwm2m/src/main/data/models/10366.xml | 2 +- transport/lwm2m/src/main/data/models/10368.xml | 2 +- transport/lwm2m/src/main/data/models/10369.xml | 2 +- transport/lwm2m/src/main/data/models/2048.xml | 2 +- transport/lwm2m/src/main/data/models/2049.xml | 2 +- transport/lwm2m/src/main/data/models/2050.xml | 2 +- transport/lwm2m/src/main/data/models/2051.xml | 2 +- transport/lwm2m/src/main/data/models/2052.xml | 2 +- transport/lwm2m/src/main/data/models/2053.xml | 2 +- transport/lwm2m/src/main/data/models/2054.xml | 2 +- transport/lwm2m/src/main/data/models/2055.xml | 2 +- transport/lwm2m/src/main/data/models/2056.xml | 2 +- transport/lwm2m/src/main/data/models/2057.xml | 2 +- transport/lwm2m/src/main/data/models/31024.xml | 2 +- transport/lwm2m/src/main/data/models/3200.xml | 2 +- transport/lwm2m/src/main/data/models/3201.xml | 2 +- transport/lwm2m/src/main/data/models/3202.xml | 2 +- transport/lwm2m/src/main/data/models/3203.xml | 2 +- transport/lwm2m/src/main/data/models/3300.xml | 2 +- transport/lwm2m/src/main/data/models/3301.xml | 2 +- transport/lwm2m/src/main/data/models/3302.xml | 2 +- transport/lwm2m/src/main/data/models/3303.xml | 2 +- transport/lwm2m/src/main/data/models/3304.xml | 2 +- transport/lwm2m/src/main/data/models/3305.xml | 2 +- transport/lwm2m/src/main/data/models/3306.xml | 2 +- transport/lwm2m/src/main/data/models/3308.xml | 2 +- transport/lwm2m/src/main/data/models/3310.xml | 2 +- transport/lwm2m/src/main/data/models/3311.xml | 2 +- transport/lwm2m/src/main/data/models/3312.xml | 2 +- transport/lwm2m/src/main/data/models/3313.xml | 2 +- transport/lwm2m/src/main/data/models/3314.xml | 2 +- transport/lwm2m/src/main/data/models/3315.xml | 2 +- transport/lwm2m/src/main/data/models/3316.xml | 2 +- transport/lwm2m/src/main/data/models/3317.xml | 2 +- transport/lwm2m/src/main/data/models/3318.xml | 2 +- transport/lwm2m/src/main/data/models/3319.xml | 2 +- transport/lwm2m/src/main/data/models/3320.xml | 2 +- transport/lwm2m/src/main/data/models/3321.xml | 2 +- transport/lwm2m/src/main/data/models/3322.xml | 2 +- transport/lwm2m/src/main/data/models/3323.xml | 2 +- transport/lwm2m/src/main/data/models/3324.xml | 2 +- transport/lwm2m/src/main/data/models/3325.xml | 2 +- transport/lwm2m/src/main/data/models/3326.xml | 2 +- transport/lwm2m/src/main/data/models/3327.xml | 2 +- transport/lwm2m/src/main/data/models/3328.xml | 2 +- transport/lwm2m/src/main/data/models/3329.xml | 2 +- transport/lwm2m/src/main/data/models/3330.xml | 2 +- transport/lwm2m/src/main/data/models/3331.xml | 2 +- transport/lwm2m/src/main/data/models/3332.xml | 2 +- transport/lwm2m/src/main/data/models/3333.xml | 2 +- transport/lwm2m/src/main/data/models/3334.xml | 2 +- transport/lwm2m/src/main/data/models/3335.xml | 2 +- transport/lwm2m/src/main/data/models/3336.xml | 2 +- transport/lwm2m/src/main/data/models/3337.xml | 2 +- transport/lwm2m/src/main/data/models/3338.xml | 2 +- transport/lwm2m/src/main/data/models/3339.xml | 2 +- transport/lwm2m/src/main/data/models/3340.xml | 2 +- transport/lwm2m/src/main/data/models/3341.xml | 2 +- transport/lwm2m/src/main/data/models/3342.xml | 2 +- transport/lwm2m/src/main/data/models/3343.xml | 2 +- transport/lwm2m/src/main/data/models/3344.xml | 2 +- transport/lwm2m/src/main/data/models/3345.xml | 2 +- transport/lwm2m/src/main/data/models/3346.xml | 2 +- transport/lwm2m/src/main/data/models/3347.xml | 2 +- transport/lwm2m/src/main/data/models/3348.xml | 2 +- transport/lwm2m/src/main/data/models/3349.xml | 2 +- transport/lwm2m/src/main/data/models/3350.xml | 2 +- transport/lwm2m/src/main/data/models/3351.xml | 2 +- transport/lwm2m/src/main/data/models/3352.xml | 2 +- transport/lwm2m/src/main/data/models/3353.xml | 2 +- transport/lwm2m/src/main/data/models/3354.xml | 2 +- transport/lwm2m/src/main/data/models/3355.xml | 2 +- transport/lwm2m/src/main/data/models/3356.xml | 2 +- transport/lwm2m/src/main/data/models/3357.xml | 2 +- transport/lwm2m/src/main/data/models/3358.xml | 2 +- transport/lwm2m/src/main/data/models/3359.xml | 2 +- transport/lwm2m/src/main/data/models/3360.xml | 2 +- transport/lwm2m/src/main/data/models/3361.xml | 2 +- transport/lwm2m/src/main/data/models/3362.xml | 2 +- transport/lwm2m/src/main/data/models/3363.xml | 2 +- transport/lwm2m/src/main/data/models/3364.xml | 2 +- transport/lwm2m/src/main/data/models/3365.xml | 2 +- transport/lwm2m/src/main/data/models/3366.xml | 2 +- transport/lwm2m/src/main/data/models/3367.xml | 2 +- transport/lwm2m/src/main/data/models/3368.xml | 2 +- transport/lwm2m/src/main/data/models/3369.xml | 2 +- transport/lwm2m/src/main/data/models/3370.xml | 2 +- transport/lwm2m/src/main/data/models/3371.xml | 2 +- transport/lwm2m/src/main/data/models/3372.xml | 2 +- transport/lwm2m/src/main/data/models/3373.xml | 2 +- transport/lwm2m/src/main/data/models/3374.xml | 2 +- transport/lwm2m/src/main/data/models/3375.xml | 2 +- transport/lwm2m/src/main/data/models/3376.xml | 2 +- transport/lwm2m/src/main/data/models/3377.xml | 2 +- transport/lwm2m/src/main/data/models/3378.xml | 2 +- transport/lwm2m/src/main/data/models/3379.xml | 2 +- .../lwm2m/src/main/data/models/3380-2_0.xml | 2 +- transport/lwm2m/src/main/data/models/3381.xml | 2 +- transport/lwm2m/src/main/data/models/3382.xml | 2 +- transport/lwm2m/src/main/data/models/3383.xml | 2 +- transport/lwm2m/src/main/data/models/3384.xml | 2 +- transport/lwm2m/src/main/data/models/3385.xml | 2 +- transport/lwm2m/src/main/data/models/3386.xml | 2 +- .../LWM2M_APN_Connection_Profile-v1_0_1.xml | 2 +- .../models/LWM2M_Bearer_Selection-v1_0_1.xml | 2 +- .../LWM2M_Cellular_Connectivity-v1_0_1.xml | 2 +- .../main/data/models/LWM2M_DevCapMgmt-v1_0.xml | 2 +- .../main/data/models/LWM2M_LOCKWIPE-v1_0_1.xml | 2 +- .../main/data/models/LWM2M_Portfolio-v1_0.xml | 2 +- .../models/LWM2M_Software_Component-v1_0.xml | 2 +- .../models/LWM2M_Software_Management-v1_0.xml | 2 +- .../models/LWM2M_WLAN_connectivity4-v1_0.xml | 2 +- .../main/data/models/LwM2M_EventLog-V1_0.xml | 2 +- .../ThingsboardLwm2mTransportApplication.java | 2 +- .../src/main/resources/tb-lwm2m-transport.yml | 2 +- .../lwm2m-device-config-server.component.html | 2 +- .../lwm2m-device-config-server.component.ts | 2 +- ...ofile-transport-configuration.component.html | 2 +- ...profile-transport-configuration.component.ts | 2 +- ...m2m-object-add-instances-list.component.html | 2 +- ...lwm2m-object-add-instances-list.component.ts | 2 +- .../lwm2m-object-add-instances.component.html | 2 +- .../lwm2m-object-add-instances.component.ts | 2 +- .../lwm2m/lwm2m-object-list.component.html | 3 +-- .../device/lwm2m/lwm2m-object-list.component.ts | 2 +- ...serve-attr-telemetry-resource.component.html | 2 +- ...observe-attr-telemetry-resource.component.ts | 2 +- .../lwm2m-observe-attr-telemetry.component.css | 3 +-- .../lwm2m-observe-attr-telemetry.component.html | 3 +-- .../lwm2m-observe-attr-telemetry.component.ts | 2 +- .../lwm2m/lwm2m-profile-components.module.ts | 2 +- .../device/lwm2m/profile-config.models.ts | 2 +- .../lwm2m/security-config-server.component.html | 2 +- .../lwm2m/security-config-server.component.ts | 2 +- .../device/lwm2m/security-config.component.html | 2 +- .../device/lwm2m/security-config.component.ts | 2 +- .../device/lwm2m/security-config.models.ts | 2 +- 291 files changed, 307 insertions(+), 293 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceLwm2mController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceLwm2mController.java index 4ddeff5af6..5f2e946f10 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceLwm2mController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceLwm2mController.java @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2020 The Thingsboard Authors + * Copyright © 2016-2021 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MModelsRepository.java b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MModelsRepository.java index e909dd8741..81dd7d7e66 100644 --- a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MModelsRepository.java +++ b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MModelsRepository.java @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2020 The Thingsboard Authors + * Copyright © 2016-2021 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mInstance.java b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mInstance.java index 4545e4dc0a..aeff342582 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mInstance.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mInstance.java @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2020 The Thingsboard Authors + * Copyright © 2016-2021 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mObject.java b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mObject.java index 4bd700fdf9..6401e8a31a 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mObject.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mObject.java @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2020 The Thingsboard Authors + * Copyright © 2016-2021 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mResource.java b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mResource.java index 7228f02760..9317232b9d 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mResource.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mResource.java @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2020 The Thingsboard Authors + * Copyright © 2016-2021 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/ServerSecurityConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/ServerSecurityConfig.java index 3f7f1d543c..8fde14b6ca 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/ServerSecurityConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/ServerSecurityConfig.java @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2020 The Thingsboard Authors + * Copyright © 2016-2021 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/common/transport/lwm2m/pom.xml b/common/transport/lwm2m/pom.xml index 44a764be2b..00d559c9d1 100644 --- a/common/transport/lwm2m/pom.xml +++ b/common/transport/lwm2m/pom.xml @@ -1,3 +1,20 @@ + - -
Date: Wed, 27 Jan 2021 14:45:34 +0200 Subject: [PATCH 088/249] default value for prohibitDifferentUrl changed to false --- .../server/service/install/DefaultSystemDataLoaderService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java index 659df4e48f..8bec74cff9 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java @@ -197,7 +197,7 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { generalSettings.setKey("general"); ObjectNode node = objectMapper.createObjectNode(); node.put("baseUrl", "http://localhost:8080"); - node.put("prohibitDifferentUrl", true); + node.put("prohibitDifferentUrl", false); generalSettings.setJsonValue(node); adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, generalSettings); From 31b51cfc9f28ea4e8b43b8a53ce9d9e8c8eb3464 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 27 Jan 2021 16:04:20 +0200 Subject: [PATCH 089/249] Lwm2m: back: start fix --- .../transport/lwm2m/server/LwM2MTransportServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServiceImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServiceImpl.java index 8a62e5aa2a..e412e113e9 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServiceImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServiceImpl.java @@ -148,7 +148,7 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { public void onRegistered(LeshanServer lwServer, Registration registration, Collection previousObsersations) { executorRegistered.submit(() -> { try { -// log.warn("[{}] [{{}] Client: create after Registration", registration.getEndpoint(), registration.getId()); + log.warn("[{}] [{{}] Client: create after Registration", registration.getEndpoint(), registration.getId()); LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.updateInSessionsLwM2MClient(lwServer, registration); if (lwM2MClient != null) { lwM2MClient.setLwM2MTransportServiceImpl(this); From e4fe3f399b2a6cfbe6811a226b42866938ac2c4d Mon Sep 17 00:00:00 2001 From: PetrTodorov Date: Thu, 28 Jan 2021 15:11:50 +0100 Subject: [PATCH 090/249] Updated Czech translation --- .../assets/locale/locale.constant-cs_CZ.json | 574 +++++++++++++++++- 1 file changed, 561 insertions(+), 13 deletions(-) diff --git a/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json b/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json index 8483fb1113..28fb3a4b48 100644 --- a/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json +++ b/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json @@ -54,7 +54,10 @@ "share-via": "Sdílet přes {{provider}}", "continue": "Pokračovat", "discard-changes": "Zahodit změny", - "download": "Stáhnout" + "download": "Stáhnout", + "next-with-label": "Další: {{label}}", + "read-more": "Zobrazit více", + "hide": "Skrýt" }, "aggregation": { "aggregation": "Agregace", @@ -77,6 +80,8 @@ "test-mail-sent": "Testovací zpráva byla úspěšně odeslána!", "base-url": "Základní URL", "base-url-required": "Hodnota Základní URL je povinná.", + "prohibit-different-url": "Zakázat použití názvu hosta z hlaviček požadavku klienta", + "prohibit-different-url-hint": "Toto nastavení by mělo být povoleno v produkčních prostředích. Pokud je zakázáno, může způsobit bezpečnostní problémy", "mail-from": "Email od", "mail-from-required": "Hodnota Email od je povinná.", "smtp-protocol": "SMTP protokol", @@ -99,6 +104,33 @@ "proxy-user": "Uživatel proxy", "proxy-password": "Heslo proxy", "send-test-mail": "Odeslat testovací zprávu", + "sms-provider": "Poskytovatel SMS", + "sms-provider-settings": "Nastavení poskytovatele SMS", + "sms-provider-type": "Typ poskytovatele SMS", + "sms-provider-type-required": "Typ poskytovatele SMS je povinný.", + "sms-provider-type-aws-sns": "Amazon SNS", + "sms-provider-type-twilio": "Twilio", + "aws-access-key-id": "AWS Access Key ID", + "aws-access-key-id-required": "AWS Access Key ID je povinný", + "aws-secret-access-key": "AWS Secret Access Key", + "aws-secret-access-key-required": "AWS Secret Access Key je povinný", + "aws-region": "AWS Region", + "aws-region-required": "AWS Region je povinný", + "number-from": "Telefonní číslo odesílatele", + "number-from-required": "Telefonní číslo Odesílatele je povinné.", + "number-to": "Telefonní číslo příjemce", + "number-to-required": "Telefonní číslo příjemce je povinné.", + "phone-number-hint": "Telefonní číslo ve formátu E.164, např. +19995550123", + "phone-number-pattern": "Neplatné telefonní číslo. Mělo by odpovídat formátu E.164, např. +19995550123.", + "sms-message": "SMS zpráva", + "sms-message-required": "SMS zpráva je povinná.", + "sms-message-max-length": "SMS zpráva nemůže být delší než 1600 znaků", + "twilio-account-sid": "Twilio Account SID", + "twilio-account-sid-required": "Twilio Account SID je povinné", + "twilio-account-token": "Twilio Account Token", + "twilio-account-token-required": "Twilio Account Token je povinný", + "send-test-sms": "Odeslat testovací SMS", + "test-sms-sent": "Testovací SMS úspěšně odeslána!", "security-settings": "Bezpečnostní nastavení", "password-policy": "Politika hesel", "minimum-password-length": "Minimální délka hesla", @@ -119,8 +151,74 @@ "general-policy": "Obecná politika", "max-failed-login-attempts": "Maximální počet neúspěšných pokusů o přihlášení před zablokováním účtu", "minimum-max-failed-login-attempts-range": "Maximální počet neúspěšných pokusů o přihlášení před zablokováním účtu nemůže být záporný", - "user-lockout-notification-email": "V případě zablokování uživatelského účtu odeslat upozornění na email" - }, + "user-lockout-notification-email": "V případě zablokování uživatelského účtu odeslat upozornění na email", + "domain-name": "Doménové jméno", + "domain-name-unique": "Doménové jméno a protokol musí být unikátní.", + "error-verification-url": "Doménové jméno by nemělo obsahovat symbol '/' ani ':'. Příklad: thingsboard.io", + "oauth2": { + "access-token-uri": "URI přístupového tokenu", + "access-token-uri-required": "URI přístupového tokenu je povinné.", + "activate-user": "Aktivovat uživatele", + "add-domain": "Přidat doménu", + "delete-domain": "Smazat doménu", + "add-provider": "Přidat poskytovatele", + "delete-provider": "Smazat poskytovatele", + "allow-user-creation": "Povolit vytvoření uživatele", + "always-fullscreen": "Vždy v režimu celé obrazovky", + "authorization-uri": "Autorizační URI", + "authorization-uri-required": "Autorizační URI je povinné.", + "client-authentication-method": "Metoda autentizace klienta", + "client-id": "ID klienta", + "client-id-required": "ID klienta je povinné.", + "client-secret": "Heslo klienta", + "client-secret-required": "Heslo klienta je povinné.", + "custom-setting": "Vlastní nastavení", + "customer-name-pattern": "Vzor názvu zákazníka", + "default-dashboard-name": "Název defaultního dashboardu", + "delete-domain-text": "Budťe opatrní, protože po potvrzení nebudou doména ani žádná data poskytovatele dostupné.", + "delete-domain-title": "Jste si jisti, že chcete smazat nastavení domény '{{domainName}}'?", + "delete-registration-text": "Buďte opatrní, protože po potvrzení nebudou data poskytovatele dostupná.", + "delete-registration-title": "Jste si jisti, že chcete smazat poskytovatele '{{name}}'?", + "email-attribute-key": "Atribut klíče email", + "email-attribute-key-required": "Atribut klíče email je povinný.", + "first-name-attribute-key": "Atribut klíče jméno", + "general": "Obecné", + "jwk-set-uri": "JSON Web Key URI", + "last-name-attribute-key": "Atribut klíče příjmení", + "login-button-icon": "Ikona tlačítka přihlášení", + "login-button-label": "Označení poskytovatele", + "login-button-label-placeholder": "Přihlásit se přes $(Provider label)", + "login-button-label-required": "Označení je povinné.", + "login-provider": "Poskytovatel přihlášení", + "mapper": "Mapper", + "new-domain": "Nová doména", + "oauth2": "OAuth2", + "redirect-uri-template": "Šablona URI přesměrování", + "copy-redirect-uri": "Zkopírovat URI přesměrování", + "registration-id": "ID registrace", + "registration-id-required": "ID registrace je povinné.", + "registration-id-unique": "Id registrace musí být v systému unikátní.", + "scope": "Rozsah", + "scope-required": "Rozsah je povinný.", + "tenant-name-pattern": "Vzor názvu tenanta", + "tenant-name-pattern-required": "Vzor názvu tenanta je povinný.", + "tenant-name-strategy": "Strategie názvu tenanta", + "type": "Typ mapperu", + "uri-pattern-error": "Neplatný formát URI.", + "url": "URL", + "url-pattern": "Neplatný formát URL.", + "url-required": "URL je povinná.", + "user-info-uri": "User info URI", + "user-info-uri-required": "User info URI je povinné.", + "user-name-attribute-name": "Atribut klíče název uživatele", + "user-name-attribute-name-required": "Atribut klíče název uživatele je povinný", + "protocol": "Protokol", + "domain-schema-http": "HTTP", + "domain-schema-https": "HTTPS", + "domain-schema-mixed": "HTTP+HTTPS", + "enable": "Povolit nastavení OAuth2" + } + }, "alarm": { "alarm": "Alarm", "alarms": "Alarmy", @@ -128,6 +226,8 @@ "no-alarms-matching": "Žádné alarmy odpovídající '{{entity}}' nebyly nalezeny.", "alarm-required": "Alarm je povinný", "alarm-status": "Stav alarmu", + "alarm-status-list": "Seznam stavů alarmu", + "any-status": "Všechny stavy", "search-status": { "ANY": "Všechny", "ACTIVE": "Aktivní", @@ -154,6 +254,8 @@ "end-time": "Datum ukončení", "ack-time": "Datum přijetí", "clear-time": "Datum vyřešení", + "alarm-severity-list": "Seznam závažností alarmu", + "any-severity": "Všechny závažnosti", "severity-critical": "Kritická", "severity-major": "Vysoká", "severity-minor": "Nízká", @@ -176,12 +278,16 @@ "clear-alarm-title": "Odstranit alarm", "clear-alarm-text": "Jste si jisti, že chcete alarm odstranit?", "alarm-status-filter": "Filtr stavu alarmu", + "alarm-filter": "Filtr alarmu", "max-count-load": "Maximální počet nahraných alarmů (0 - neomezeně)", "max-count-load-required": "Maximální počet nahraných alarmů je povinný.", "max-count-load-error-min": "Minimální hodnota je 0.", "fetch-size": "Velikost dávky", "fetch-size-required": "Velikost dávky je povinná.", - "fetch-size-error-min": "Minimální hodnota je 10." + "fetch-size-error-min": "Minimální hodnota je 10.", + "alarm-type-list": "Seznam typů alarmu", + "any-type": "Všechny typy", + "search-propagated-alarms": "Vyhledat zpropagované alarmy" }, "alias": { "add": "Přidat alias", @@ -211,6 +317,7 @@ "filter-type-device-search-query-description": "Zařízení typů {{deviceTypes}} se {{relationType}} vztahem {{direction}} {{rootEntity}}", "filter-type-entity-view-search-query": "Dotaz na vyhledání zobrazení entity", "filter-type-entity-view-search-query-description": "Entitní pohledy typů {{entityViewTypes}} se {{relationType}} vztahem {{direction}} {{rootEntity}}", + "filter-type-apiUsageState": "Stav využití Api", "entity-filter": "Filtr entity", "resolve-multiple": "Použít jako více entit", "filter-type": "Typ filtru", @@ -325,6 +432,59 @@ "no-attributes-text": "Žádné atributy nebyly nalezeny", "no-telemetry-text": "Žádná telemetrie nebyla nalezena" }, + "api-usage": { + "api-usage": "Využití Api", + "data-points": "Datové body", + "data-points-storage-days": "Dny uložení datových bodů", + "email": "Email", + "email-messages": "Emailové zprávy", + "email-messages-daily-activity": "Denní aktivita emailových zpráv", + "email-messages-hourly-activity": "Hodinová aktivita emailových zpráv", + "email-messages-monthly-activity": "Měsíční aktivita emailových zpráv", + "exceptions": "Výjimky", + "executions": "Zpracování", + "javascript": "JavaScript", + "javascript-executions": "JavaScript výjimky", + "javascript-functions": "JavaScript funkce", + "javascript-functions-daily-activity": "Denní aktivita JavaScript funkcí", + "javascript-functions-hourly-activity": "Hodinová aktivita JavaScript funkcí", + "javascript-functions-monthly-activity": "Měsíční aktivita JavaScript funkcí", + "latest-error": "Poslední chyba", + "messages": "Zprávy", + "permanent-failures": "${entityName} permanentní chyby", + "permanent-timeouts": "${entityName} permanentní timeouty", + "processing-failures": "${entityName} chyby zpracování", + "processing-failures-and-timeouts": "Chyby a timeouty zpracování", + "processing-timeouts": "${entityName} timeouty zpracování", + "queue-stats": "Statistiky fronty", + "rule-chain": "Řetěz pravidel", + "rule-engine": "Engine pro zpracování pravidel", + "rule-engine-daily-activity": "Denní aktivita enginu pro zpracování pravidel", + "rule-engine-executions": "Zpracování Enginu pro zpracování pravidel", + "rule-engine-hourly-activity": "Hodinová aktivita enginu pro zpracování pravidel", + "rule-engine-monthly-activity": "Měsíční aktivita enginu pro zpracování pravidel", + "rule-engine-statistics": "Statistiky enginu pro zpracování pravidel", + "rule-node": "Uzel pravidla", + "sms": "SMS", + "sms-messages": "SMS zprávy", + "sms-messages-daily-activity": "Denní aktivita SMS zpráv", + "sms-messages-hourly-activity": "Hodinová aktivita SMS zpráv", + "sms-messages-monthly-activity": "Měsíční aktivita SMS zpráv", + "successful": "${entityName} úspěšnost", + "telemetry": "Telemetrie", + "telemetry-persistence": "Uložení telemetrie", + "telemetry-persistence-daily-activity": "Denní aktivita uložení telemetrie", + "telemetry-persistence-hourly-activity": "Hodinová aktivita uložení telemetrie", + "telemetry-persistence-monthly-activity": "Měsíční aktivita uložení telemetrie", + "transport": "Přenos", + "transport-daily-activity": "Denní aktivita přenosu", + "transport-data-points": "Datové body přenosu", + "transport-hourly-activity": "Hodinová aktivita přenosu", + "transport-messages": "Zprávy přenosu", + "transport-monthly-activity": "Měsíční aktivita přenosu", + "view-details": "Zobrazit detail", + "view-statistics": "Zobrazit statistiky" + }, "audit-log": { "audit": "Audit", "audit-logs": "Záznamy auditu", @@ -363,7 +523,13 @@ "action-data": "Data akce", "failure-details": "Detail chyby", "search": "Prohledat záznamy auditu", - "clear-search": "Vymazat vyhledávání" + "clear-search": "Vymazat vyhledávání", + "type-assigned-from-tenant": "Odebráno tenantovi", + "type-assigned-to-tenant": "Přiřazeno tenantovi", + "type-provision-success": "Zřízení zařízení", + "type-provision-failure": "Selhání zřízení zařízení", + "type-timeseries-updated": "Aktualizace telemetrie", + "type-timeseries-deleted": "Smazání telemetrie" }, "confirm-on-exit": { "message": "Některé změny nebyly uloženy. Jste si jisti, že chcete tuto stránku opustit?", @@ -549,6 +715,7 @@ "title-color": "Barva názvu", "display-dashboards-selection": "Zobrazit výběr dashboardů", "display-entities-selection": "Zobrazit výběr entit", + "display-filters": "Zobrazit filtry", "display-dashboard-timewindow": "Zobrazit časové okno", "display-dashboard-export": "Zobrazit export", "import": "Importovat dashboard", @@ -615,6 +782,7 @@ "alarm": "Pole alarmu", "timeseries-required": "Časové řady entity jsou povinné.", "timeseries-or-attributes-required": "Časové řady / atributy entity jsou povinné.", + "alarm-fields-timeseries-or-attributes-required": "Pole alarmu nebo časové řady / atributy jsou povinné.", "maximum-timeseries-or-attributes": "Maximálně { count, plural, 1 {1 časová řada/atribut je povolena.} other {# časových řad/atributů je povoleno} }", "alarm-fields-required": "Pole alarmu jsou povinná.", "function-types": "Typy funkcí", @@ -706,6 +874,12 @@ "access-token-invalid": "Délka přístupového tokenu musí být od 1 do 20 znaků.", "rsa-key": "RSA veřejný klíč", "rsa-key-required": "RSA veřejný klíč je povinný.", + "client-id": "ID klienta", + "client-id-pattern": "Obsahuje neplatné znaky.", + "user-name": "Název uživatele", + "user-name-required": "Název uživatele je povinný.", + "client-id-or-user-name-necessary": "ID klienta a/nebo název uživatele jsou povinné", + "password": "Heslo", "secret": "Heslo", "secret-required": "Heslo je povinné.", "device-type": "Typ zařízení", @@ -724,19 +898,183 @@ "details": "Detail", "copyId": "Kopírovat Id zařízení", "copyAccessToken": "Kopírovat přístupový token", + "copy-mqtt-authentication": "Kopírovat přístupové údaje MQTT", "idCopiedMessage": "Id zařízení bylo zkopírováno do schránky", "accessTokenCopiedMessage": "Přístupový token zařízení byl zkopírován do schránky", + "mqtt-authentication-copied-message": "MQTT autentizace zařízení byla zkopírována do schránky", "assignedToCustomer": "Přiřazeno zákazníkovi", "unable-delete-device-alias-title": "Nebylo možné smazat alias zařízení", "unable-delete-device-alias-text": "Alias zařízení '{{deviceAlias}}' nelze smazat, protože je používán následujícími widgety:
{{widgetsList}}", "is-gateway": "Je bránou", + "overwrite-activity-time": "Přepsat čas aktivity připojeného zařízení", "public": "Veřejné", "device-public": "Zařízení je veřejné", "select-device": "Vybrat zařízení", "import": "Importovat zařízení", "device-file": "Soubor zařízení", "search": "Vyhledat zařízení", - "selected-devices": "Vybráno { count, plural, 1 {1 zařízení} other {# zařízení} }" + "selected-devices": "Vybráno { count, plural, 1 {1 zařízení} other {# zařízení} }", + "device-configuration": "Konfigurace zařízení", + "transport-configuration": "Konfigurace přenosu", + "wizard": { + "device-wizard": "Průvodce zařízením", + "device-details": "Detail zařízení", + "new-device-profile": "Vytvořit nový profil zařízení", + "existing-device-profile": "Vybrat existující profil zařízení", + "specific-configuration": "Specifická konfigurace", + "customer-to-assign-device": "Přiřadit zařízení zákazníkovi", + "add-credential": "Přidat přístupový údaj" + } + }, + "device-profile": { + "device-profile": "Profil zařízení", + "device-profiles": "Profily zařízení", + "all-device-profiles": "Všechny", + "add": "Přidat profil zařízení", + "edit": "Editovat profil zařízení", + "device-profile-details": "Detail profilu zařízení", + "no-device-profiles-text": "Žádné profily zařízení nebyly nalezeny", + "search": "Vyhledat profily zařízení", + "selected-device-profiles": "Vybráno { count, plural, 1 {1 profil zařízení} other {# profilů zařízení} }", + "no-device-profiles-matching": "Žádný profil zařízení odpovídající '{{entity}}' nebyl nalezen.", + "device-profile-required": "Profil zařízení je povinný", + "idCopiedMessage": "Id profilu zařízení bylo zkopírováno do schránky", + "set-default": "Učinit profil zařízení defaultním", + "delete": "Smazat profil zařízení", + "copyId": "Kopírovat Id profilu zařízení", + "new-device-profile-name": "Název profilu zařízení", + "new-device-profile-name-required": "Název profilu zařízení je povinný.", + "name": "Název", + "name-required": "Název je povinný.", + "type": "Typ profilu", + "type-required": "Typ profilu je povinný.", + "type-default": "Defaultní", + "transport-type": "Typ přenosu", + "transport-type-required": "Typ přenosu je povinný.", + "transport-type-default": "Defaultní", + "transport-type-default-hint": "Podporuje základní MQTT, HTTP and CoAP přenos", + "transport-type-mqtt": "MQTT", + "transport-type-mqtt-hint": "Umožňuje pokročilé nastavení MQTT přenosu", + "transport-type-lwm2m": "LWM2M", + "transport-type-lwm2m-hint": "Typ transportu LWM2M", + "description": "Popis", + "default": "Defaultní", + "profile-configuration": "Konfigurace profilu", + "transport-configuration": "Konfigurace přenosu", + "default-rule-chain": "Defaultní řetěz pravidel", + "select-queue-hint": "Vyberte z rozbalovacího seznamu nebo přidejte vlastní název.", + "delete-device-profile-title": "Jste si jisti, že chcete smazat profil zařízení '{{deviceProfileName}}'?", + "delete-device-profile-text": "Buďte opatrní, protože po potvrzení nebude možné profil zařízení ani žádná související data obnovit.", + "delete-device-profiles-title": "Jste si jisti, že chcete smazat { count, plural, 1 {1 profil zařízení} other {# profilů zařízení} }?", + "delete-device-profiles-text": "Buďte opatrní, protože po potvrzení budou všechny vybrané profily zařízení odstraněny a žádná související data nebude možné obnovit.", + "set-default-device-profile-title": "Jste si jisti, že chcete profil zařízení '{{deviceProfileName}}' učinit defaultním?", + "set-default-device-profile-text": "Po potvrzení bude profil zařízení označen jako defaultní a bude použit pro nová zařízení bez specifikovaného profilu.", + "no-device-profiles-found": "Žádné profily zařízení nebyly nalezeny.", + "create-new-device-profile": "Vytvořit nový!", + "mqtt-device-topic-filters": "Filtry MQTT fronty zařízení", + "mqtt-device-topic-filters-unique": "Filtry MQTT fronty zařízení musí být unikátní.", + "mqtt-device-payload-type": "MQTT zpráva zařízení", + "mqtt-device-payload-type-json": "JSON", + "mqtt-device-payload-type-proto": "Protobuf", + "mqtt-payload-type-required": "Typ zprávy je povinný.", + "support-level-wildcards": "Jsou podporovány jednoúrovňové [+] a víceúrovňové [#] zástupné znaky.", + "telemetry-topic-filter": "Filtr fronty telemetrie", + "telemetry-topic-filter-required": "Filtr fronty telemetrie je povinný.", + "attributes-topic-filter": "Filtr atributů fronty", + "attributes-topic-filter-required": "Filtr atributů fronty je povinný.", + "telemetry-proto-schema": "Proto schéma telemetrie", + "telemetry-proto-schema-required": "Proto schéma telemetrie je povinné.", + "attributes-proto-schema": "Atributy proto schémata", + "attributes-proto-schema-required": "Atributy proto schémata jsou povinné.", + "rpc-response-topic-filter": "Filtr fronty RPC odpovědi", + "rpc-response-topic-filter-required": "Filtr fronty RPC odpovědi je povinný.", + "not-valid-pattern-topic-filter": "Neplatný vzor filtru fronty", + "not-valid-single-character": "Neplatné použití jednoúrovňového zástupného znaku", + "not-valid-multi-character": "Neplatné použití víceúrovňového zástupného znaku", + "single-level-wildcards-hint": "[+] je vhodný pro jakoukoli úroveň filtru fronty. Př.: v1/devices/+/telemetry or +/devices/+/attributes.", + "multi-level-wildcards-hint": "[#] může nahradit filtr fronty a může se jednat o poslední symbol fronty. Př.: # or v1/devices/me/#.", + "alarm-rules": "Pravidla alarmu", + "alarm-rules-with-count": "Pravidla alarmu ({{count}})", + "no-alarm-rules": "Žádná pravidla alarmu nejsou konfigurována", + "add-alarm-rule": "Přidat pravidlo alarmu", + "edit-alarm-rule": "Editovat pravidlo alarmu", + "alarm-type": "Typ alarmu", + "alarm-type-required": "Typ alarmu je povinný.", + "alarm-type-unique": "Typ alarmu musí být v rámci pravidel alarmu profilu zařízení unikátní.", + "create-alarm-pattern": "Vytvořit {{alarmType}} alarm", + "create-alarm-rules": "Vytvořit pravidla alarmu", + "no-create-alarm-rules": "Nejsou konfigurovány žádné podmínky vytvoření", + "add-create-alarm-rule-prompt": "Přidejte prosím pravidlo vytvoření alarmu", + "clear-alarm-rule": "Pravidlo zrušení alarmu", + "no-clear-alarm-rule": "Není konfigurována žádná podmínka zrušení", + "add-create-alarm-rule": "Přidat podmínku vytvoření", + "add-clear-alarm-rule": "Přidat podmínku zrušení", + "select-alarm-severity": "Vybrat závažnost alarmu", + "alarm-severity-required": "Závažnost alarmu je povinná.", + "condition-duration": "Doba trvání podmínky", + "condition-duration-value": "Hodnota doby trvání", + "condition-duration-time-unit": "Jednotka času", + "condition-duration-value-range": "Hodnota doby trvání musí být v rozsahu od 1 do 2147483647.", + "condition-duration-value-pattern": "Doba trvání musí být celé číslo.", + "condition-duration-value-required": "Doba trvání je povinná.", + "condition-duration-time-unit-required": "Jednotka času je povinná.", + "advanced-settings": "Pokročilá nastavení", + "alarm-rule-details": "Detail", + "add-alarm-rule-details": "Přidat detail", + "propagate-alarm": "Propagovat alarm", + "alarm-rule-relation-types-list": "Typy vztahů ke zpropagování", + "alarm-rule-relation-types-list-hint": "Pokud nejsou vybrány žádné typy vztahů, alarmy budou propagovány bez filtru typu vztahu.", + "alarm-details": "Detail alarmu", + "alarm-rule-condition": "Podmínka pravidla alarmu", + "enter-alarm-rule-condition-prompt": "Přidejte prosím podmínku pravidla alarmu", + "edit-alarm-rule-condition": "Editovat podmínku pravidla alarmu", + "device-provisioning": "Zřízení zařízení", + "provision-strategy": "Strategie zřízení", + "provision-strategy-required": "Strategie zřízení je povinná.", + "provision-strategy-disabled": "Zakázáno", + "provision-strategy-created-new": "Povolit vytváření nových zařízení", + "provision-strategy-check-pre-provisioned": "Zkontrolovat předvytvořená zařízení", + "provision-device-key": "Klíč pro zřízení zařízení", + "provision-device-key-required": "Klíč pro zřízení zařízení je povinný.", + "copy-provision-key": "Kopírovat klíč pro zřízení", + "provision-key-copied-message": "Klíč pro zřízení byl zkopírován do schránky", + "provision-device-secret": "Heslo pro zřízení zařízení", + "provision-device-secret-required": "Heslo pro zřízení zařízení je povinné.", + "copy-provision-secret": "Kopírovat heslo pro zřízení", + "provision-secret-copied-message": "Heslo pro zřízení zařízení bylo zkopírováno do schránky", + "condition": "Podmínka", + "condition-type": "Typ podmínky", + "condition-type-simple": "Jednoduchá", + "condition-type-duration": "Doba trvání", + "condition-during": "V průběhu {{during}}", + "condition-type-repeating": "Opakování", + "condition-type-required": "Typ podmínky je povinný.", + "condition-repeating-value": "Počet událostí", + "condition-repeating-value-range": "Počet událostí musí být v rozsahu od 1 do 2147483647.", + "condition-repeating-value-pattern": "Počet událostí musí být celé číslo.", + "condition-repeating-value-required": "Počet událostí je povinný.", + "condition-repeat-times": "Opakování { count, plural, 1 {1 krát} other {# krát} }", + "schedule-type": "Typ plánovače", + "schedule-type-required": "Typ plánovače je povinný.", + "schedule": "Časový plán", + "edit-schedule": "Editovat časový plán alarmu", + "schedule-any-time": "Aktivní neustále", + "schedule-specific-time": "Aktivní v konkrétním čase", + "schedule-custom": "Vlastní", + "schedule-day": { + "monday": "Pondělí", + "tuesday": "Úterý", + "wednesday": "Středa", + "thursday": "Čtvrtek", + "friday": "Pátek", + "saturday": "Sobota", + "sunday": "Neděle" + }, + "schedule-days": "Dny", + "schedule-time": "Čas", + "schedule-time-from": "Od", + "schedule-time-to": "Do", + "schedule-days-of-week-required": "Musí být vybrán minimálně jeden den v týdnu." }, "dialog": { "close": "Zavřít dialog" @@ -757,7 +1095,7 @@ "entity-alias": "Alias entity", "unable-delete-entity-alias-title": "Alias entity nebylo možné smazat", "unable-delete-entity-alias-text": "Alias entity '{{entityAlias}}' nelze smazat, protože je používán následujícími widgety:
{{widgetsList}}", - "duplicate-alias-error": "Nalezen dupliticní alias '{{alias}}'.
Aliasy entit musí být v rámci dashboardu unikátní.", + "duplicate-alias-error": "Nalezen duplicitní alias '{{alias}}'.
Aliasy entit musí být v rámci dashboardu unikátní.", "missing-entity-filter-error": "Ve filtru chybí alias '{{alias}}'.", "configure-alias": "Konfigurovat '{{alias}}' alias", "alias": "Alias", @@ -794,6 +1132,10 @@ "type-devices": "Zařízení", "list-of-devices": "{ count, plural, 1 {Jedno zařízení} other {Seznam # zařízení} }", "device-name-starts-with": "Zařízení, jejichž název začíná '{{prefix}}'", + "type-device-profile": "Profil zařízení", + "type-device-profiles": "Profily zařízení", + "list-of-device-profiles": "{ count, plural, 1 {Jeden profil zařízení} other {Seznam # profilů zařízení} }", + "device-profile-name-starts-with": "Profily zařízení, jejichž název začíná '{{prefix}}'", "type-asset": "Aktivum", "type-assets": "Aktiva", "list-of-assets": "{ count, plural, 1 {Jedno aktivum} other {Seznam # aktiv} }", @@ -814,6 +1156,10 @@ "type-tenants": "Tenanti", "list-of-tenants": "{ count, plural, 1 {Jeden tenant} other {Seznam # tenantů} }", "tenant-name-starts-with": "Tenanti, jejichž název začíná '{{prefix}}'", + "type-tenant-profile": "Profil tenanta", + "type-tenant-profiles": "Profily tenantů", + "list-of-tenant-profiles": "{ count, plural, 1 {Jeden profil tenanta} other {Seznam # profilů tenantů} }", + "tenant-profile-name-starts-with": "Profily tenantů, jejichž název začíná '{{prefix}}'", "type-customer": "Zákazník", "type-customers": "Zákazníci", "list-of-customers": "{ count, plural, 1 {Jeden zákazník} other {Seznam # zákazníků} }", @@ -840,6 +1186,8 @@ "rulenode-name-starts-with": "Uzly pravidel, jejichž název začíná '{{prefix}}'", "type-current-customer": "Stávající zákazník", "type-current-tenant": "Stávající tenant", + "type-current-user": "Stávající uživatel", + "type-current-user-owner": "Vlastník stávajícího uživatele", "search": "Vyhledat entity", "selected-entities": "{ count, plural, 1 {1 entita} other {# entit} } zvoleno", "entity-name": "Název entity", @@ -847,7 +1195,8 @@ "details": "Detail entity", "no-entities-prompt": "Žádné entity nebyly nalezeny", "no-data": "Nelze zobrazit žádná data", - "columns-to-display": "Zobrazit sloupce" + "columns-to-display": "Zobrazit sloupce", + "type-api-usage-state": "Stav využití API" }, "entity-field": { "created-time": "Datum vytvoření", @@ -1048,7 +1397,7 @@ "anonymous": "Anonymní", "basic": "Základní", "pem": "PEM", - "ca-cert": "soubor CA certifikátu *", + "ca-cert": "Soubor CA certifikátu *", "private-key": "Soubor privátního klíče *", "cert": "Soubor certifikátu *", "no-file": "Žádný soubor nebyl vybrán.", @@ -1154,6 +1503,93 @@ "file": "Soubor rozšíření", "invalid-file-error": "Neplatný soubor rozšíření" }, + "filter": { + "add": "Přidat filtr", + "edit": "Editovat filtr", + "name": "Název filtru", + "name-required": "Název filtru je povinný.", + "duplicate-filter": "Filtr s identickým názvem již existuje.", + "filters": "Filtry", + "unable-delete-filter-title": "Smazat filtr není možné", + "unable-delete-filter-text": "Filtr '{{filter}}' není možné smazat, protože je používán následujícím widgetem(y):
{{widgetsList}}", + "duplicate-filter-error": "Nalezen duplicitní filtr '{{filter}}'.
Filtry musí být v rámci dashboardu unikátní.", + "missing-key-filters-error": "U filtru '{{filter}}' chybí klíčové filtry.", + "filter": "Filtr", + "editable": "Editovatelné", + "no-filters-found": "Žádné filtry nebyly nalezeny.", + "no-filter-text": "Není specifikován žádný filtr", + "add-filter-prompt": "Přidejte prosím filtr", + "no-filter-matching": "'{{filter}}' nebyl nalezen.", + "create-new-filter": "Vytvořit nový!", + "filter-required": "Filtr je povinný.", + "operation": { + "operation": "Operace", + "equal": "je rovno", + "not-equal": "není rovno", + "starts-with": "začíná na", + "ends-with": "končí na", + "contains": "obsahuje", + "not-contains": "neobsahuje", + "greater": "větší než", + "less": "menší než", + "greater-or-equal": "větší nebo rovno", + "less-or-equal": "menší nebo rovno", + "and": "a", + "or": "nebo" + }, + "ignore-case": "ignorovat velikost písmen", + "value": "Hodnota", + "remove-filter": "Odebrat filtr", + "preview": "Náhled filtru", + "no-filters": "Nejsou konfigurovány žádné filtry", + "add-filter": "Přidat filtr", + "add-complex-filter": "Přidat komplexní filtr", + "add-complex": "Přidat komplex", + "complex-filter": "Komplexní filtr", + "edit-complex-filter": "Editovat komplexní filtr", + "edit-filter-user-params": "Editovat filtr predikátu parametrů uživatele", + "filter-user-params": "Filtr predikátu parametrů uživatele", + "user-parameters": "Parametry uživatele", + "display-label": "Zobrazované označení", + "autogenerated-label": "Automaticky vygenerovat označení", + "order-priority": "Priority pořadí polí", + "key-filter": "Klíčový filtr", + "key-filters": "Klíčové filtry", + "key-name": "Název klíče", + "key-name-required": "Název klíče je povinný.", + "key-type": { + "key-type": "Typ klíče", + "attribute": "Atribut", + "timeseries": "Časové řady", + "entity-field": "Pole entity" + }, + "value-type": { + "value-type": "Typ hodnoty", + "string": "Řetězec", + "numeric": "Číslo", + "boolean": "Pravdivostní hodnota", + "date-time": "Datum a čas" + }, + "value-type-required": "Typ hodnoty klíče je povinný.", + "key-value-type-change-title": "Jste si jisti, že chcete změnit typ klíče hodnoty?", + "key-value-type-change-message": "Pokud potvrdíte nový typ hodnoty, všechny zadané klíčové filtry budou odstraněny.", + "no-key-filters": "Nejsou konfigurovány žádné klíčové filtry", + "add-key-filter": "Přidat klíčový filtr", + "remove-key-filter": "Odebrat klíčový filtr", + "edit-key-filter": "Editovat klíčový filtr", + "date": "Datum", + "time": "Čas", + "current-tenant": "Stávající tenant", + "current-customer": "Stávající zákazník", + "current-user": "Stávající uživatel", + "current-device": "Stávající zařízení", + "default-value": "Defaultní hodnota", + "dynamic-source-type": "Dynamický typ zdroje", + "no-dynamic-value": "Žádná dynamická hodnota", + "source-attribute": "Atribut zdroje", + "switch-to-dynamic-value": "Přepnout na dynamickou hodnotu", + "switch-to-default-value": "Přepnout na defaultní hodnotu" + }, "fullscreen": { "expand": "Rozšířit do režimu celé obrazovky", "exit": "Ukončit režim celé obrazovky", @@ -1286,6 +1722,7 @@ "entity-field": "Pole entity", "access-token": "Přístupový token", "isgateway": "Je bránou", + "activity-time-from-gateway-device": "Čas aktivity ze zařízení brány", "description": "Popis" }, "stepper-text":{ @@ -1329,6 +1766,7 @@ "legend": { "direction": "Směr legendy", "position": "Pozice legendy", + "sort-legend": "Setřídit datové klíče v legendě", "show-max": "Zobrazit max hodnotu", "show-min": "Zobrazit min hodnotu", "show-avg": "Zobrazit průměrnou hodnotu", @@ -1525,6 +1963,12 @@ "help": "Nápověda", "reset-debug-mode": "Resetovat režim ladění na všech uzlech" }, + "timezone": { + "timezone": "Časová zóna", + "select-timezone": "Vyberte časovou zónu", + "no-timezones-matching": "žádné časové zóny odpovídající '{{timezone}}' nebyly nalezeny.", + "timezone-required": "Časová zóna je povinná." + }, "queue": { "select_name": "Vybrat název fronty", "name": "Název fronty", @@ -1563,6 +2007,87 @@ "isolated-tb-core-details": "Vyžaduje samostatnou mikroslužbu(y) pro každého izolovaného tenanta", "isolated-tb-rule-engine-details": "Vyžaduje samostatnou mikroslužbu(y) pro každého izolovaného tenanta" }, + "tenant-profile": { + "tenant-profile": "Profil tenanta", + "tenant-profiles": "Profily tenantů", + "add": "Přidat profil tenanta", + "edit": "Editovat profil tenanta", + "tenant-profile-details": "Detail profilu tenanta", + "no-tenant-profiles-text": "Nebyly nalezeny žádné profily tenantů", + "search": "Vyhledat profily tenantů", + "selected-tenant-profiles": "Vybráno { count, plural, 1 {1 profilů tenantů} other {# profilů tenantů} }", + "no-tenant-profiles-matching": "Žádné profily tenantů odpovídající '{{entity}}' nebyly nalezeny.", + "tenant-profile-required": "Profil tenanta je povinný", + "idCopiedMessage": "Id profilu tenanta bylo zkopírováno do schránky", + "set-default": "Učinit profil tenanta defaultním", + "delete": "Smazat profil tenanta", + "copyId": "Kopírovat Id profilu tenanta", + "name": "Název", + "name-required": "Název je povinný.", + "data": "Data profilu", + "profile-configuration": "Konfigurace profilu", + "description": "Popis", + "default": "Defaultní", + "delete-tenant-profile-title": "Jste si jisti, že chcete smazat profil tenanta '{{tenantProfileName}}'?", + "delete-tenant-profile-text": "Buďte opatrní, protože po potvrzení nebude možné profil tenanta ani žádná související data obnovit.", + "delete-tenant-profiles-title": "Jste si jisti, že chcete smazat { count, plural, 1 {1 profil tenanta} other {# profilů tenanta} }?", + "delete-tenant-profiles-text": "Buďte opatrní, protože po potvrzení budou všechny vybrané profily tenantů odstraněny a žádná související data nebude možné obnovit.", + "set-default-tenant-profile-title": "Jste si jisti, že chcete učinit profil tenanta '{{tenantProfileName}}' defaultním?", + "set-default-tenant-profile-text": "Po potvrzení bude profil tenanta označen jako defaultní a bude použit pro nové tenanty bez specifikovaného profilu.", + "no-tenant-profiles-found": "Nebyly nalezeny žádné profily tenantů.", + "create-new-tenant-profile": "Vytvořit nový!", + "maximum-devices": "Maximální počet zařízení (0 - neomezeno)", + "maximum-devices-required": "Maximální počet zařízení je povinný.", + "maximum-devices-range": "Minimální počet zařízení nemůže být záporný", + "maximum-assets": "Maximální počet aktiv (0 - neomezeno)", + "maximum-assets-required": "Maximální počet aktiv je povinný.", + "maximum-assets-range": "Maximální počet aktiv nemůže být záporný", + "maximum-customers": "Maximální počet zákazníků (0 - neomezeno)", + "maximum-customers-required": "Maximální počet zákazníkůje povinný.", + "maximum-customers-range": "Maximální počet zákazníků nemůže být záporný", + "maximum-users": "Maximální počet uživatelů (0 - neomezeno)", + "maximum-users-required": "Maximální počet uživatelů je povinný.", + "maximum-users-range": "Maximální počet uživatelů nemůže být záporný", + "maximum-dashboards": "Maximální počet dashboardů (0 - neomezeno)", + "maximum-dashboards-required": "Maximální počet dashboardů je povinný.", + "maximum-dashboards-range": "Maximální počet dashboardů nemůže být záporný", + "maximum-rule-chains": "Maximální počet řetězů pravidel (0 - neomezeno)", + "maximum-rule-chains-required": "Maximální počet řetězů pravidel je povinný.", + "maximum-rule-chains-range": "Maximální počet řetězů pravidel nemůže být záporný", + "transport-tenant-msg-rate-limit": "Limit přenosu zpráv tenanta.", + "transport-tenant-telemetry-msg-rate-limit": "Limit přenosu zpráv telemetrie tenanta.", + "transport-tenant-telemetry-data-points-rate-limit": "Limit přenosu datových bodů telemetrie tenanta.", + "transport-device-msg-rate-limit": "Limit přenosu zpráv zařízení.", + "transport-device-telemetry-msg-rate-limit": "Limit přenosu zpráv zařízení telemetrie tenanta.", + "transport-device-telemetry-data-points-rate-limit": "Limit přenosu datových bodů zařízení telemetrie tenanta.", + "max-transport-messages": "Maximální počet zpráv přenosu (0 - neomezeno)", + "max-transport-messages-required": "Maximální počet zpráv přenosu je povinný.", + "max-transport-messages-range": "Maximální počet zpráv přenosu nemůže být záporný", + "max-transport-data-points": "Maximální počet datových bodů přenosu (0 - neomezeno)", + "max-transport-data-points-required": "Maximální počet datových bodů přenosu je povinný.", + "max-transport-data-points-range": "Maximální počet datových bodů přenosu nemůže být záporný", + "max-r-e-executions": "Maximální počet zpracování enginu pro zpracování pravidel (0 - neomezeno)", + "max-r-e-executions-required": "Maximální počet zpracování enginu pro zpracování pravidel je povinný.", + "max-r-e-executions-range": "Maximální počet zpracování enginu pro zpracování pravidel nemůže být záporný", + "max-j-s-executions": "Maximální počet JavaScript zpracování (0 - neomezeno)", + "max-j-s-executions-required": "Maximální počet JavaScript zpracování je povinný.", + "max-j-s-executions-range": "Maximální počet JavaScript zpracování nemůže být záporný", + "max-d-p-storage-days": "Maximální počet dnů uložení datových bodů (0 - neomezeno)", + "max-d-p-storage-days-required": "Maximální počet dnů uložení datových bodů je povinný.", + "max-d-p-storage-days-range": "Maximální počet dnů uložení datových bodů nemůže být záporný", + "default-storage-ttl-days": "Defaultní počet dnů TTL úložiště (0 - neomezeno)", + "default-storage-ttl-days-required": "Defaultní počet dnů TTL úložiště je povinný.", + "default-storage-ttl-days-range": "Defaultní počet dnů TTL úložiště nemůže být záporný", + "max-rule-node-executions-per-message": "Maximální počet zpracování uzlů pravidel na zprávu (0 - neomezeno)", + "max-rule-node-executions-per-message-required": "Maximální počet zpracování uzlů pravidel na zprávu je povinný.", + "max-rule-node-executions-per-message-range": "Maximální počet zpracování uzlů pravidel na zprávu nemůže být záporný", + "max-emails": "Maximální počet odeslaných emailů (0 - neomezeno)", + "max-emails-required": "Maximální počet odeslaných emailů je povinný.", + "max-emails-range": "Maximální počet odeslaných emailů nemůže být záporný", + "max-sms": "Maximální počet odeslaných SMS (0 - neomezeno)", + "max-sms-required": "Maximální počet odeslaných SMS je povinný.", + "max-sms-range": "Maximální počet odeslaných SMS nemůže být záporný" + }, "timeinterval": { "seconds-interval": "{ seconds, plural, 1 {1 vteřina} other {# vteřin} }", "minutes-interval": "{ minutes, plural, 1 {1 minuta} other {# minut} }", @@ -1574,8 +2099,14 @@ "seconds": "Vteřiny", "advanced": "Rozšířené" }, + "timeunit": { + "seconds": "Vteřiny", + "minutes": "Minuty", + "hours": "Hodiny", + "days": "Dny" + }, "timewindow": { - "days": "{ days, plural, 1 { den } other {# days } }", + "days": "{ days, plural, 1 { den } other {# dnů } }", "hours": "{ hours, plural, 0 { hodina } 1 {1 hodina } other {# hodin } }", "minutes": "{ minutes, plural, 0 { minuta } 1 {1 minuta } other {# minut } }", "seconds": "{ seconds, plural, 0 { vteřina } 1 {1 vteřina } other {# vteřin } }", @@ -1694,6 +2225,7 @@ "type": "Typ widgetu", "resources": "Zdroje", "resource-url": "JavaScript/CSS URL", + "resource-is-module": "Je modulem", "remove-resource": "Odebrat zdroj", "add-resource": "Přidat zdroj", "html": "HTML", @@ -1711,7 +2243,10 @@ "widget-template-load-failed-error": "Nahrání šablony widgetu selhalo!", "add": "Přidat widget", "undo": "Vrátit změny widgetu", - "export": "Exportovat widget" + "export": "Exportovat widget", + "no-data": "Nejsou k dispozici žádná data pro zobrazení ve widgetu", + "data-overflow": "Widget zobrazuje {{count}} z {{total}} entit", + "alarm-data-overflow": "Widget zobrazuje alarmy {{allowedEntities}} (maxima možných) entit z {{totalEntities}} entit" }, "widget-action": { "header-button": "Tlačítko hlavičky widgetu", @@ -1724,7 +2259,14 @@ "target-dashboard-state-required": "Cílový stav dashboardu je povinný", "set-entity-from-widget": "Nastavit entitu z widgetu", "target-dashboard": "Cílový dashboard", - "open-right-layout": "Otevřít rozmístění dashboardu vpravo (mobilní zobrazení)" + "open-right-layout": "Otevřít rozmístění dashboardu vpravo (mobilní zobrazení)", + "open-in-separate-dialog": "Otevřít v samostatném okně", + "dialog-title": "Název okna", + "dialog-hide-dashboard-toolbar": "Skrýt v okně nástrojovou lištu dashboardu", + "dialog-width": "Šířka okna v procentech vzhledem k šířce obrazovky", + "dialog-height": "Výška okna v procentech vzhledem k výšce obrazovky", + "dialog-size-range-error": "Hodnota procentuální velikosti musí být v rozsahu od 1 do 100.", + "open-new-browser-tab": "Otevřít na nové záložce prohlížeče" }, "widgets-bundle": { "current": "Vybraná kategorie", @@ -1891,8 +2433,11 @@ "entity-coordinate-required": "Obě pole, zeměpisná šířka i zeměpisná délka, jsou povinná", "entity-timeseries-required": "Časové řady entity jsou povinné", "get-location": "Získat aktuální polohu", + "invalid-date": "Neplatné datum", "latitude": "Zeměpisná šířka", "longitude": "Zeměpisná délka", + "min-value-error": "Minimální hodnota je {{value}}", + "max-value-error": "Maximální hodnota je {{value}}", "not-allowed-entity": "Vybraná entita nemůže mít sdílené atributy", "no-attribute-selected": "Není vybrán žádný atribut", "no-datakey-selected": "Není vybrán žádný datový klíč", @@ -1900,7 +2445,10 @@ "no-entity-selected": "Není vybrána žádná entita", "no-image": "Žádný obrázek", "no-support-geolocation": "Váš prohlížeč nepodporuje geolokaci", - "no-support-web-camera": "Žádná podporovaná webová kamera", + "no-support-web-camera": "Váš prohlížeč nepodporuje kamery", + "enable-https-use-widget": "Prosím povolte HTTPS abyste mohli používat tento widget", + "no-found-your-camera": "Nelze nalézt vyši kameru", + "no-permission-camera": "Přístup byl zakázán uživatelem / Tato stránka nemá oprávnění použít kameru", "no-timeseries-selected": "Nejsou vybrány žádné časové řady", "secret-key": "Tajný klíč", "secret-key-required": "Tajný klíč je povinný", From ac89b188f2913b9f14dd9beadb45a9e4974e993f Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Thu, 28 Jan 2021 16:53:13 +0200 Subject: [PATCH 091/249] Lwm2m: front: fix any bug --- .../lwm2m-device-config-server.component.ts | 5 +- ...ile-transport-configuration.component.html | 2 +- ...ofile-transport-configuration.component.ts | 122 +++++++++--------- .../device/lwm2m/profile-config.models.ts | 13 +- 4 files changed, 72 insertions(+), 70 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts index 441bc71eeb..b61b35296d 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts @@ -51,6 +51,7 @@ import { TranslateService } from '@ngx-translate/core'; export class Lwm2mDeviceConfigServerComponent implements ControlValueAccessor { private requiredValue: boolean; + private disabled = false; valuePrev = null; serverFormGroup: FormGroup; @@ -61,10 +62,6 @@ export class Lwm2mDeviceConfigServerComponent implements ControlValueAccessor { lenMaxServerPublicKey = LEN_MAX_PUBLIC_KEY_RPK; currentSecurityMode = null; - - @Input() - disabled: boolean; - @Input() bootstrapServerIs: boolean; diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html index 3b728c8d1f..312f0cf4a3 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -
+
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts index f63af09457..c77cdbf8c0 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts @@ -21,16 +21,12 @@ import { Store } from '@ngrx/store'; import { AppState } from '@app/core/core.state'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { - ATTR, + ID, INSTANCES, RESOURCES, OBSERVE_ATTR_TELEMETRY, OBSERVE, ATTRIBUTE, TELEMETRY, KEY_NAME, getDefaultProfileConfig, Instance, - KEY_NAME, ObjectLwM2M, - OBSERVE, - OBSERVE_ATTR, ProfileConfigModels, - ResourceLwM2M, - TELEMETRY + ResourceLwM2M } from './profile-config.models'; import { DeviceProfileService } from '@core/http/device-profile.service'; import { deepClone, isDefinedAndNotNull, isUndefined } from '@core/utils'; @@ -55,11 +51,6 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro lwm2mDeviceProfileFormGroup: FormGroup; lwm2mDeviceConfigFormGroup: FormGroup; - observeAttr = OBSERVE_ATTR; - observe = OBSERVE; - attribute = ATTR; - telemetry = TELEMETRY; - keyName = KEY_NAME; bootstrapServers: string; bootstrapServer: string; lwm2mServer: string; @@ -199,22 +190,22 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro private getObserveAttrTelemetryObjects = (listObject: ObjectLwM2M[]): object => { const clientObserveAttrTelemetry = listObject; - if (this.configurationValue[this.observeAttr]) { - const observeArray = this.configurationValue[this.observeAttr][this.observe]; - const attributeArray = this.configurationValue[this.observeAttr][this.attribute]; - const telemetryArray = this.configurationValue[this.observeAttr][this.telemetry]; - const keyNameJson = this.configurationValue[this.observeAttr][this.keyName]; + if (this.configurationValue.observeAttr) { + const observeArray = this.configurationValue.observeAttr.observe; + const attributeArray = this.configurationValue.observeAttr.attribute; + const telemetryArray = this.configurationValue.observeAttr.telemetry; + const keyNameJson = this.configurationValue.observeAttr.keyName; if (this.includesNotZeroInstance(attributeArray, telemetryArray)) { this.addInstances(attributeArray, telemetryArray, clientObserveAttrTelemetry); } if (isDefinedAndNotNull(observeArray)) { - this.updateObserveAttrTelemetryObjects(observeArray, clientObserveAttrTelemetry, 'observe'); + this.updateObserveAttrTelemetryObjects(observeArray, clientObserveAttrTelemetry, OBSERVE); } if (isDefinedAndNotNull(attributeArray)) { - this.updateObserveAttrTelemetryObjects(attributeArray, clientObserveAttrTelemetry, 'attribute'); + this.updateObserveAttrTelemetryObjects(attributeArray, clientObserveAttrTelemetry, ATTRIBUTE); } if (isDefinedAndNotNull(telemetryArray)) { - this.updateObserveAttrTelemetryObjects(telemetryArray, clientObserveAttrTelemetry, 'telemetry'); + this.updateObserveAttrTelemetryObjects(telemetryArray, clientObserveAttrTelemetry, TELEMETRY); } if (isDefinedAndNotNull(keyNameJson)) { this.updateKeyNameObjects(keyNameJson, clientObserveAttrTelemetry); @@ -279,35 +270,43 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro let pathRes; observeJson.forEach(obj => { for (const [key, value] of Object.entries(obj)) { - if (key === 'id') { + if (key === ID) { pathObj = value; } - if (key === 'instances') { + if (key === INSTANCES) { const instancesJson = value as Instance[]; if (instancesJson.length > 0) { instancesJson.forEach(instance => { for (const [instanceKey, instanceValue] of Object.entries(instance)) { - if (instanceKey === 'id') { + if (instanceKey === ID) { pathInst = instanceValue; } - if (instanceKey === 'resources') { + if (instanceKey === RESOURCES) { const resourcesJson = instanceValue as ResourceLwM2M[]; if (resourcesJson.length > 0) { resourcesJson.forEach(res => { for (const [resourceKey, value] of Object.entries(res)) { - if (resourceKey === 'id') { + if (resourceKey === ID) { pathRes = `/${pathObj}/${pathInst}/${value}`; - } else if (resourceKey === 'observe' && value) { - observeArray.push(pathRes); - } else if (resourceKey === 'attribute' && value) { + } else if (resourceKey === ATTRIBUTE && value) { attributeArray.push(pathRes); paths.add(pathRes); - } else if (resourceKey === 'telemetry' && value) { + } else if (resourceKey === TELEMETRY && value) { telemetryArray.push(pathRes); paths.add(pathRes); } - else if (resourceKey === this.keyName && paths.has(pathRes)) { - console.warn(pathRes, value); + } + }); + /** + * only if these paths are marked in ATTRIBUTE or TELEMETRY + */ + resourcesJson.forEach(res => { + for (const [resourceKey, value] of Object.entries(res)) { + if (resourceKey === ID) { + pathRes = `/${pathObj}/${pathInst}/${value}`; + } else if (resourceKey === OBSERVE && paths.has(pathRes) && value) { + observeArray.push(pathRes); + } else if (resourceKey === KEY_NAME && paths.has(pathRes)) { keyNameNew[pathRes] = value; } } @@ -320,27 +319,28 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } } }); - if (isUndefined(this.configurationValue[this.observeAttr])) { - this.configurationValue[this.observeAttr] = { - [this.observe]: observeArray, - [this.attribute]: attributeArray, - [this.telemetry]: telemetryArray + if (isUndefined(this.configurationValue.observeAttr)) { + this.configurationValue.observeAttr = { + observe: observeArray, + attribute: attributeArray, + telemetry: telemetryArray, + keyName: this.sortObjectKeyPathJson(KEY_NAME, keyNameNew) }; } else { - this.configurationValue[this.observeAttr][this.observe] = observeArray; - this.configurationValue[this.observeAttr][this.attribute] = attributeArray; - this.configurationValue[this.observeAttr][this.telemetry] = telemetryArray; + 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[this.observeAttr][this.keyName] = this.sortObjectKeyPathJson('keyName', keyNameNew); } sortObjectKeyPathJson = (key: string, value: object): object => { - if (key === 'keyName') { + if (key === KEY_NAME) { return Object.keys(value).sort(this.sortPath).reduce((obj, keySort) => { obj[keySort] = value[keySort]; return obj; }, {}); - } else if (key === 'observe' || key === 'attribute' || key === 'telemetry') { + } else if (key === OBSERVE || key === ATTRIBUTE || key === TELEMETRY) { return Object.values(value).sort(this.sortPath).reduce((arr, arrValue) => { arr.push(arrValue); return arr; @@ -359,19 +359,19 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro private getObjectsFromJsonAllConfig = (): number[] => { const objectsIds = new Set(); - if (this.configurationValue[this.observeAttr]) { - if (this.configurationValue[this.observeAttr][this.observe]) { - this.configurationValue[this.observeAttr][this.observe].forEach(obj => { + if (this.configurationValue.observeAttr) { + if (this.configurationValue.observeAttr.observe) { + this.configurationValue.observeAttr.observe.forEach(obj => { objectsIds.add(Array.from(obj.substring(1).split('/'), Number)[0]); }); } - if (this.configurationValue[this.observeAttr][this.attribute]) { - this.configurationValue[this.observeAttr][this.attribute].forEach(obj => { + if (this.configurationValue.observeAttr.attribute) { + this.configurationValue.observeAttr.attribute.forEach(obj => { objectsIds.add(Array.from(obj.substring(1).split('/'), Number)[0]); }); } - if (this.configurationValue[this.observeAttr][this.telemetry]) { - this.configurationValue[this.observeAttr][this.telemetry].forEach(obj => { + if (this.configurationValue.observeAttr.telemetry) { + this.configurationValue.observeAttr.telemetry.forEach(obj => { objectsIds.add(Array.from(obj.substring(1).split('/'), Number)[0]); }); } @@ -390,15 +390,15 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } removeObjectsList = (value: ObjectLwM2M): void => { - const objectsOld = this.lwm2mDeviceProfileFormGroup.get('observeAttrTelemetry').value.clientLwM2M; + const objectsOld = this.lwm2mDeviceProfileFormGroup.get(OBSERVE_ATTR_TELEMETRY).value.clientLwM2M; const isIdIndex = (element) => element.id === value.id; const index = objectsOld.findIndex(isIdIndex); if (index >= 0) { objectsOld.splice(index, 1); } - this.removeObserveAttrTelemetryFromJson(this.observe, value.id); - this.removeObserveAttrTelemetryFromJson(this.telemetry, value.id); - this.removeObserveAttrTelemetryFromJson(this.attribute, value.id); + this.removeObserveAttrTelemetryFromJson(OBSERVE, value.id); + this.removeObserveAttrTelemetryFromJson(TELEMETRY, value.id); + this.removeObserveAttrTelemetryFromJson(ATTRIBUTE, value.id); this.removeKeyNameFromJson(value.id); this.updateObserveAttrTelemetryObjectFormGroup(objectsOld); this.upDateJsonAllConfig(); @@ -406,15 +406,15 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro private removeObserveAttrTelemetryFromJson = (observeAttrTel: string, id: number): void => { const isIdIndex = (element) => element.startsWith(`/${id}`); - let index = this.configurationValue[this.observeAttr][observeAttrTel].findIndex(isIdIndex); + let index = this.configurationValue.observeAttr[observeAttrTel].findIndex(isIdIndex); while (index >= 0) { - this.configurationValue[this.observeAttr][observeAttrTel].splice(index, 1); - index = this.configurationValue[this.observeAttr][observeAttrTel].findIndex(isIdIndex, index); + this.configurationValue.observeAttr[observeAttrTel].splice(index, 1); + index = this.configurationValue.observeAttr[observeAttrTel].findIndex(isIdIndex, index); } } private removeKeyNameFromJson = (id: number): void => { - const keyNameJson = this.configurationValue[this.observeAttr][this.keyName]; + const keyNameJson = this.configurationValue.observeAttr.keyName; Object.keys(keyNameJson).forEach(key => { if (key.startsWith(`/${id}`)) { delete keyNameJson[key]; @@ -423,17 +423,17 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } isPathInJson(path: string): boolean { - let isPath = this.findPathInJson(path, this.attribute); + let isPath = this.findPathInJson(path, ATTRIBUTE); if (!isPath) { - isPath = this.findPathInJson(path, this.telemetry); + isPath = this.findPathInJson(path, TELEMETRY); } return !!isPath; } private findPathInJson = (path: string, side: string): string => { - if (this.configurationValue[this.observeAttr]) { - if (this.configurationValue[this.observeAttr][side]) { - return this.configurationValue[this.observeAttr][side].find( + if (this.configurationValue.observeAttr) { + if (this.configurationValue.observeAttr[side]) { + return this.configurationValue.bootstrap[side].find( pathJs => pathJs === path); } } diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/profile-config.models.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/profile-config.models.ts index 49ed272821..583cc72a44 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/profile-config.models.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/profile-config.models.ts @@ -14,9 +14,14 @@ /// limitations under the License. /// -export const OBSERVE_ATTR = 'observeAttr'; +import { JsonObject } from '@angular/compiler-cli/ngcc/src/packages/entry_point'; + +export const ID = 'id'; +export const INSTANCES = 'instances'; +export const RESOURCES = 'resources'; +export const OBSERVE_ATTR_TELEMETRY = 'observeAttrTelemetry'; export const OBSERVE = 'observe'; -export const ATTR = 'attribute'; +export const ATTRIBUTE = 'attribute'; export const TELEMETRY = 'telemetry'; export const KEY_NAME = 'keyName'; export const DEFAULT_ID_SERVER = 123; @@ -89,7 +94,7 @@ export interface ObservableAttributes { observe: string[]; attribute: string[]; telemetry: string[]; - keyName: string[]; + keyName: {}; } export function getDefaultBootstrapServersSecurityConfig(): BootstrapServersSecurityConfig { @@ -138,7 +143,7 @@ export function getDefaultProfileConfig(hostname?: any): ProfileConfigModels { observe: [], attribute: [], telemetry: [], - keyName: [] + keyName: {} } }; } From 70f9da07d8bf7b620cf3d5ab950344c2c80b114b Mon Sep 17 00:00:00 2001 From: AndrewVolostnykhThingsboard Date: Thu, 28 Jan 2021 17:01:59 +0200 Subject: [PATCH 092/249] CassandraBaseTimeseriesDao init method fix (revert) --- .../timeseries/CassandraBaseTimeseriesDao.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java index e7b951f16d..f0888055f2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java @@ -116,16 +116,16 @@ public class CassandraBaseTimeseriesDao extends AbstractCassandraBaseTimeseriesD super.startExecutor(); if (!isInstall()) { getFetchStmt(Aggregation.NONE, DESC_ORDER); - Optional partition = NoSqlTsPartitionDate.parse(partitioning); - if (partition.isPresent()) { - tsFormat = partition.get(); - if (!isFixedPartitioning() && partitionsCacheSize > 0) { - cassandraTsPartitionsCache = new CassandraTsPartitionsCache(partitionsCacheSize); - } - } else { - log.warn("Incorrect configuration of partitioning {}", partitioning); - throw new RuntimeException("Failed to parse partitioning property: " + partitioning + "!"); + } + Optional partition = NoSqlTsPartitionDate.parse(partitioning); + if (partition.isPresent()) { + tsFormat = partition.get(); + if (!isFixedPartitioning() && partitionsCacheSize > 0) { + cassandraTsPartitionsCache = new CassandraTsPartitionsCache(partitionsCacheSize); } + } else { + log.warn("Incorrect configuration of partitioning {}", partitioning); + throw new RuntimeException("Failed to parse partitioning property: " + partitioning + "!"); } } From 5029445b8c6018151073ff000799d13ba7e92db7 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Thu, 28 Jan 2021 18:59:57 +0200 Subject: [PATCH 093/249] Deduplication of the partition change events --- .../state/DefaultDeviceStateService.java | 21 +--- .../utils/EventDeduplicationExecutor.java | 85 +++++++++++++ .../util/EventDeduplicationExecutorTest.java | 119 ++++++++++++++++++ 3 files changed, 210 insertions(+), 15 deletions(-) create mode 100644 application/src/main/java/org/thingsboard/server/utils/EventDeduplicationExecutor.java create mode 100644 application/src/test/java/org/thingsboard/server/util/EventDeduplicationExecutorTest.java diff --git a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java index 75577fc5a4..b1d47c9864 100644 --- a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java @@ -59,6 +59,7 @@ import org.thingsboard.server.queue.discovery.PartitionService; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.queue.TbClusterService; import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; +import org.thingsboard.server.utils.EventDeduplicationExecutor; import javax.annotation.Nullable; import javax.annotation.PostConstruct; @@ -126,13 +127,13 @@ public class DefaultDeviceStateService implements DeviceStateService { @Getter private int initFetchPackSize; - private volatile boolean clusterUpdatePending = false; - private ListeningScheduledExecutorService queueExecutor; private final ConcurrentMap> partitionedDevices = new ConcurrentHashMap<>(); private final ConcurrentMap deviceStates = new ConcurrentHashMap<>(); private final ConcurrentMap deviceLastReportedActivity = new ConcurrentHashMap<>(); private final ConcurrentMap deviceLastSavedActivity = new ConcurrentHashMap<>(); + private volatile EventDeduplicationExecutor> deduplicationExecutor; + public DefaultDeviceStateService(TenantService tenantService, DeviceService deviceService, AttributesService attributesService, TimeseriesService tsService, @@ -155,6 +156,7 @@ public class DefaultDeviceStateService implements DeviceStateService { // Should be always single threaded due to absence of locks. queueExecutor = MoreExecutors.listeningDecorator(Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("device-state"))); queueExecutor.scheduleAtFixedRate(this::updateState, new Random().nextInt(defaultStateCheckIntervalInSec), defaultStateCheckIntervalInSec, TimeUnit.SECONDS); + deduplicationExecutor = new EventDeduplicationExecutor<>(DefaultDeviceStateService.class.getSimpleName(), queueExecutor, this::initStateFromDB); } @PreDestroy @@ -292,25 +294,14 @@ public class DefaultDeviceStateService implements DeviceStateService { } } - volatile Set pendingPartitions; - @Override public void onApplicationEvent(PartitionChangeEvent partitionChangeEvent) { if (ServiceType.TB_CORE.equals(partitionChangeEvent.getServiceType())) { - synchronized (this) { - pendingPartitions = partitionChangeEvent.getPartitions(); - if (!clusterUpdatePending) { - clusterUpdatePending = true; - queueExecutor.submit(() -> { - clusterUpdatePending = false; - initStateFromDB(); - }); - } - } + deduplicationExecutor.submit(partitionChangeEvent.getPartitions()); } } - private void initStateFromDB() { + private void initStateFromDB(Set pendingPartitions) { try { log.info("CURRENT PARTITIONS: {}", partitionedDevices.keySet()); log.info("NEW PARTITIONS: {}", pendingPartitions); diff --git a/application/src/main/java/org/thingsboard/server/utils/EventDeduplicationExecutor.java b/application/src/main/java/org/thingsboard/server/utils/EventDeduplicationExecutor.java new file mode 100644 index 0000000000..1c67868740 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/utils/EventDeduplicationExecutor.java @@ -0,0 +1,85 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.utils; + +import lombok.extern.slf4j.Slf4j; + +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.function.Consumer; + +/** + * This class deduplicate executions of the specified function. + * Useful in cluster mode, when you get event about partition change multiple times. + * Assuming that the function execution is expensive, we should execute it immediately when first time event occurs and + * later, once the processing of first event is done, process last pending task. + * + * @param

parameters of the function + */ +@Slf4j +public class EventDeduplicationExecutor

{ + private final String name; + private final ExecutorService executor; + private final Consumer

function; + private P pendingTask; + private boolean busy; + + public EventDeduplicationExecutor(String name, ExecutorService executor, Consumer

function) { + this.name = name; + this.executor = executor; + this.function = function; + } + + public void submit(P params) { + log.info("[{}] Going to submit: {}", name, params); + synchronized (EventDeduplicationExecutor.this) { + if (!busy) { + busy = true; + pendingTask = null; + try { + log.info("[{}] Submitting task: {}", name, params); + executor.submit(() -> { + try { + log.info("[{}] Executing task: {}", name, params); + function.accept(params); + } catch (Throwable e) { + log.warn("Failed to process task with parameters: {}", params, e); + throw e; + } finally { + unlockAndProcessIfAny(); + } + }); + } catch (Throwable e) { + log.warn("Failed to submit task with parameters: {}", params, e); + unlockAndProcessIfAny(); + throw e; + } + } else { + log.info("[{}] Task is already in progress. {} pending task: {}", name, pendingTask == null ? "adding" : "updating", params); + pendingTask = params; + } + } + } + + private void unlockAndProcessIfAny() { + synchronized (EventDeduplicationExecutor.this) { + busy = false; + if (pendingTask != null) { + submit(pendingTask); + } + } + } +} diff --git a/application/src/test/java/org/thingsboard/server/util/EventDeduplicationExecutorTest.java b/application/src/test/java/org/thingsboard/server/util/EventDeduplicationExecutorTest.java new file mode 100644 index 0000000000..26718b6624 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/util/EventDeduplicationExecutorTest.java @@ -0,0 +1,119 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.util; + +import com.google.common.util.concurrent.MoreExecutors; +import lombok.extern.slf4j.Slf4j; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; +import org.thingsboard.server.utils.EventDeduplicationExecutor; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.function.Consumer; + +@Slf4j +@RunWith(MockitoJUnitRunner.class) +public class EventDeduplicationExecutorTest { + + @Test + public void testSimpleFlowSameThread() throws InterruptedException { + simpleFlow(MoreExecutors.newDirectExecutorService()); + } + + @Test + public void testPeriodicFlowSameThread() throws InterruptedException { + periodicFlow(MoreExecutors.newDirectExecutorService()); + } + + + @Test + public void testSimpleFlowSingleThread() throws InterruptedException { + simpleFlow(Executors.newFixedThreadPool(1)); + } + + @Test + public void testPeriodicFlowSingleThread() throws InterruptedException { + periodicFlow(Executors.newFixedThreadPool(1)); + } + + @Test + public void testSimpleFlowMultiThread() throws InterruptedException { + simpleFlow(Executors.newFixedThreadPool(3)); + } + + @Test + public void testPeriodicFlowMultiThread() throws InterruptedException { + periodicFlow(Executors.newFixedThreadPool(3)); + } + + private void simpleFlow(ExecutorService executorService) throws InterruptedException { + try { + Consumer function = Mockito.spy(StringConsumer.class); + EventDeduplicationExecutor executor = new EventDeduplicationExecutor<>(EventDeduplicationExecutorTest.class.getSimpleName(), executorService, function); + + String params1 = "params1"; + String params2 = "params2"; + String params3 = "params3"; + + executor.submit(params1); + executor.submit(params2); + executor.submit(params3); + Thread.sleep(500); + Mockito.verify(function).accept(params1); + Mockito.verify(function).accept(params3); + } finally { + executorService.shutdownNow(); + } + } + + private void periodicFlow(ExecutorService executorService) throws InterruptedException { + try { + Consumer function = Mockito.spy(StringConsumer.class); + EventDeduplicationExecutor executor = new EventDeduplicationExecutor<>(EventDeduplicationExecutorTest.class.getSimpleName(), executorService, function); + + String params1 = "params1"; + String params2 = "params2"; + String params3 = "params3"; + + executor.submit(params1); + Thread.sleep(500); + executor.submit(params2); + Thread.sleep(500); + executor.submit(params3); + Thread.sleep(500); + Mockito.verify(function).accept(params1); + Mockito.verify(function).accept(params2); + Mockito.verify(function).accept(params3); + } finally { + executorService.shutdownNow(); + } + } + + public static class StringConsumer implements Consumer { + @Override + public void accept(String s) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } + +} From e32e90932bc9d87051124c802f5ac703d3c39692 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Thu, 28 Jan 2021 19:27:24 +0200 Subject: [PATCH 094/249] Lwm2m: front: fix bug updateObserve...ToJson --- ...ofile-transport-configuration.component.ts | 66 +++++-------------- 1 file changed, 17 insertions(+), 49 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts index c77cdbf8c0..5277c791cc 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts @@ -264,59 +264,27 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro const telemetryArray: Array = []; const keyNameNew = {}; const observeJson: ObjectLwM2M[] = JSON.parse(JSON.stringify(val)); - const paths = new Set(); - let pathObj; - let pathInst; - let pathRes; observeJson.forEach(obj => { - for (const [key, value] of Object.entries(obj)) { - if (key === ID) { - pathObj = value; - } - if (key === INSTANCES) { - const instancesJson = value as Instance[]; - if (instancesJson.length > 0) { - instancesJson.forEach(instance => { - for (const [instanceKey, instanceValue] of Object.entries(instance)) { - if (instanceKey === ID) { - pathInst = instanceValue; - } - if (instanceKey === RESOURCES) { - const resourcesJson = instanceValue as ResourceLwM2M[]; - if (resourcesJson.length > 0) { - resourcesJson.forEach(res => { - for (const [resourceKey, value] of Object.entries(res)) { - if (resourceKey === ID) { - pathRes = `/${pathObj}/${pathInst}/${value}`; - } else if (resourceKey === ATTRIBUTE && value) { - attributeArray.push(pathRes); - paths.add(pathRes); - } else if (resourceKey === TELEMETRY && value) { - telemetryArray.push(pathRes); - paths.add(pathRes); - } - } - }); - /** - * only if these paths are marked in ATTRIBUTE or TELEMETRY - */ - resourcesJson.forEach(res => { - for (const [resourceKey, value] of Object.entries(res)) { - if (resourceKey === ID) { - pathRes = `/${pathObj}/${pathInst}/${value}`; - } else if (resourceKey === OBSERVE && paths.has(pathRes) && value) { - observeArray.push(pathRes); - } else if (resourceKey === KEY_NAME && paths.has(pathRes)) { - keyNameNew[pathRes] = value; - } - } - }); - } + if (obj.hasOwnProperty(INSTANCES) && Array.isArray(obj.instances)) { + obj.instances.forEach(instance => { + if (instance.hasOwnProperty(RESOURCES) && Array.isArray(instance.resources)) { + instance.resources.forEach(resource => { + let pathRes = `/${obj.id}/${instance.id}/${resource.id}`; + if (resource.attribute) { + attributeArray.push(pathRes); + } + if (resource.telemetry) { + telemetryArray.push(pathRes); + } + if (resource.attribute || resource.telemetry) { + keyNameNew[pathRes] = resource.keyName; + if (resource.observe) { + observeArray.push(pathRes); } } - }); + }) } - } + }) } }); if (isUndefined(this.configurationValue.observeAttr)) { From 4382c0c4b872986e830257b33cf9040f2fca63b9 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Fri, 29 Jan 2021 09:05:53 +0200 Subject: [PATCH 095/249] Lwm2m: front: fix bug2 updateObserve...ToJson --- ...-profile-transport-configuration.component.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts index 5277c791cc..2aa835d6d7 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts @@ -269,18 +269,18 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro obj.instances.forEach(instance => { if (instance.hasOwnProperty(RESOURCES) && Array.isArray(instance.resources)) { instance.resources.forEach(resource => { - let pathRes = `/${obj.id}/${instance.id}/${resource.id}`; - if (resource.attribute) { - attributeArray.push(pathRes); - } - if (resource.telemetry) { - telemetryArray.push(pathRes); - } if (resource.attribute || resource.telemetry) { - keyNameNew[pathRes] = resource.keyName; + let pathRes = `/${obj.id}/${instance.id}/${resource.id}`; if (resource.observe) { observeArray.push(pathRes); } + if (resource.attribute) { + attributeArray.push(pathRes); + } + if (resource.telemetry) { + telemetryArray.push(pathRes); + } + keyNameNew[pathRes] = resource.keyName; } }) } From d56c33ddb120d180f8ebb5bbfeafa4540c9af81e Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Fri, 29 Jan 2021 12:44:31 +0200 Subject: [PATCH 096/249] Lwm2m: front: refactoring --- .../lwm2m-device-config-server.component.ts | 2 +- ...ofile-transport-configuration.component.ts | 14 ++++---- ...m2m-object-add-instances-list.component.ts | 1 - .../lwm2m-object-add-instances.component.ts | 3 +- .../lwm2m/lwm2m-object-list.component.ts | 5 ++- ...serve-attr-telemetry-resource.component.ts | 1 - .../lwm2m-observe-attr-telemetry.component.ts | 33 ++++++++++--------- .../device/lwm2m/profile-config.models.ts | 7 +++- 8 files changed, 33 insertions(+), 33 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts index b61b35296d..adc7fcaa65 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts @@ -139,7 +139,7 @@ export class Lwm2mDeviceConfigServerComponent implements ControlValueAccessor { Validators.maxLength(this.lenMaxServerPublicKey)]); } - writeValue(value: any): void { + writeValue(value: ServerSecurityConfig): void { if (value) { this.updateValueFields(value); } diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts index 2aa835d6d7..ab3fa4f7b4 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts @@ -21,12 +21,11 @@ import { Store } from '@ngrx/store'; import { AppState } from '@app/core/core.state'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { - ID, INSTANCES, RESOURCES, OBSERVE_ATTR_TELEMETRY, OBSERVE, ATTRIBUTE, TELEMETRY, KEY_NAME, + INSTANCES, RESOURCES, OBSERVE_ATTR_TELEMETRY, OBSERVE, ATTRIBUTE, TELEMETRY, KEY_NAME, getDefaultProfileConfig, - Instance, ObjectLwM2M, ProfileConfigModels, - ResourceLwM2M + ModelValue } from './profile-config.models'; import { DeviceProfileService } from '@core/http/device-profile.service'; import { deepClone, isDefinedAndNotNull, isUndefined } from '@core/utils'; @@ -113,7 +112,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } } - writeValue(value: any | null): void { + writeValue(value: ProfileConfigModels | null): void { this.configurationValue = (Object.keys(value).length === 0) ? getDefaultProfileConfig() : value; this.lwm2mDeviceConfigFormGroup.patchValue({ configurationJson: this.configurationValue @@ -122,7 +121,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } private initWriteValue = (): void => { - const modelValue = {objectIds: null, objectsList: []}; + const modelValue = {objectIds: null, objectsList: []} as ModelValue; modelValue.objectIds = this.getObjectsFromJsonAllConfig(); if (modelValue.objectIds !== null) { const sortOrder = { @@ -140,11 +139,10 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } } - private updateWriteValue = (value: any): void => { - const objectsList = value.objectsList; + private updateWriteValue = (value: ModelValue): void => { this.lwm2mDeviceProfileFormGroup.patchValue({ objectIds: value, - observeAttrTelemetry: this.getObserveAttrTelemetryObjects(objectsList), + observeAttrTelemetry: this.getObserveAttrTelemetryObjects(value['objectsList']), shortId: this.configurationValue.bootstrap.servers.shortId, lifetime: this.configurationValue.bootstrap.servers.lifetime, defaultMinPeriod: this.configurationValue.bootstrap.servers.defaultMinPeriod, diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.ts index c556cef7c8..d1f47d4d03 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.ts @@ -25,7 +25,6 @@ import { DeviceProfileService } from '@core/http/device-profile.service'; @Component({ selector: 'tb-profile-lwm2m-object-add-instances-list', templateUrl: './lwm2m-object-add-instances-list.component.html', - styleUrls: [], providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => Lwm2mObjectAddInstancesListComponent), diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.ts index 91dbc824fc..3e482120d9 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.ts @@ -30,8 +30,7 @@ export interface Lwm2mObjectAddInstancesData { @Component({ selector: 'tb-lwm2m-object-add-instances', - templateUrl: './lwm2m-object-add-instances.component.html', - styleUrls: [] + templateUrl: './lwm2m-object-add-instances.component.html' }) export class Lwm2mObjectAddInstancesComponent extends DialogComponent implements OnInit { diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts index 718c9281d7..300f95f83f 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts @@ -21,7 +21,7 @@ import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { Observable } from 'rxjs'; import { filter, map, mergeMap, publishReplay, refCount, tap } from 'rxjs/operators'; -import { ObjectLwM2M } from './profile-config.models'; +import { ModelValue, ObjectLwM2M } from './profile-config.models'; import { TranslateService } from '@ngx-translate/core'; import { DeviceProfileService } from '@core/http/device-profile.service'; import { Direction } from '@shared/models/page/sort-order'; @@ -120,7 +120,7 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V } } - writeValue(value: any): void { + writeValue(value: ModelValue): void { this.searchText = ''; if (isDefinedAndNotNull(value)) { if (Array.isArray(value.objectIds)) { @@ -193,7 +193,6 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V return this.lw2mModels; } - onFocus = (): void => { if (!this.dirty) { this.lwm2mListFormGroup.get('objectLwm2m').updateValueAndValidity({onlySelf: true, emitEvent: true}); diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resource.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resource.component.ts index 4441a285b2..678137140d 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resource.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resource.component.ts @@ -25,7 +25,6 @@ import { coerceBooleanProperty } from '@angular/cdk/coercion'; @Component({ selector: 'tb-profile-lwm2m-observe-attr-telemetry-resource', templateUrl: './lwm2m-observe-attr-telemetry-resource.component.html', - styleUrls: [], providers: [ { provide: NG_VALUE_ACCESSOR, diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts index 2419e007c2..d53e8f241b 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts @@ -28,7 +28,7 @@ import { import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; -import { Instance, ObjectLwM2M, ResourceLwM2M } from './profile-config.models'; +import { CLIENT_LWM2M, Instance, INSTANCES, ObjectLwM2M, ResourceLwM2M, RESOURCES } from './profile-config.models'; import { deepClone, isDefinedAndNotNull, isEqual, isUndefined } from '@core/utils'; import { MatDialog } from '@angular/material/dialog'; import { TranslateService } from '@ngx-translate/core'; @@ -78,7 +78,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor private dialog: MatDialog, public translate: TranslateService) { this.observeAttrTelemetryFormGroup = this.fb.group({ - clientLwM2M: this.fb.array([]) + [CLIENT_LWM2M]: this.fb.array([]) }); this.observeAttrTelemetryFormGroup.valueChanges.subscribe(value => { if (isUndefined(this.disabled) || !this.disabled) { @@ -87,7 +87,8 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor }); } - private propagateChange = (v: any) => { }; + private propagateChange = (v: any) => { + }; registerOnChange(fn: any): void { this.propagateChange = fn; @@ -123,14 +124,14 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor } } - writeValue(value: any): void { + writeValue(value: {}): void { if (isDefinedAndNotNull(value)) { - this.buildClientObjectsLwM2M(value.clientLwM2M); + this.buildClientObjectsLwM2M(value[CLIENT_LWM2M]); } } private buildClientObjectsLwM2M = (objectsLwM2M: ObjectLwM2M []): void => { - this.observeAttrTelemetryFormGroup.setControl('clientLwM2M', + this.observeAttrTelemetryFormGroup.setControl(CLIENT_LWM2M, this.createObjectsLwM2M(objectsLwM2M) ); } @@ -157,23 +158,23 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor } get clientLwM2MFormArray(): FormArray { - return this.observeAttrTelemetryFormGroup.get('clientLwM2M') as FormArray; + return this.observeAttrTelemetryFormGroup.get(CLIENT_LWM2M) as FormArray; } instancesLwm2mFormArray = (objectLwM2M: AbstractControl): FormArray => { - return objectLwM2M.get('instances') as FormArray; + return objectLwM2M.get(INSTANCES) as FormArray; } changeInstanceResourcesCheckBox = (value: boolean, instance: AbstractControl, type: string): void => { - const resources = deepClone(instance.get('resources').value as ResourceLwM2M[]); + const resources = deepClone(instance.get(RESOURCES).value as ResourceLwM2M[]); resources.forEach(resource => resource[type] = value); - instance.get('resources').patchValue(resources); + instance.get(RESOURCES).patchValue(resources); this.propagateChange(this.observeAttrTelemetryFormGroup.value); } private updateValidators = (): void => { - this.observeAttrTelemetryFormGroup.get('clientLwM2M').setValidators(this.required ? Validators.required : []); - this.observeAttrTelemetryFormGroup.get('clientLwM2M').updateValueAndValidity(); + this.observeAttrTelemetryFormGroup.get(CLIENT_LWM2M).setValidators(this.required ? Validators.required : []); + this.observeAttrTelemetryFormGroup.get(CLIENT_LWM2M).updateValueAndValidity(); } trackByParams = (index: number, element: any): number => { @@ -181,7 +182,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor } getIndeterminate = (instance: AbstractControl, type: string): boolean => { - const resources = instance.get('resources').value as ResourceLwM2M[]; + const resources = instance.get(RESOURCES).value as ResourceLwM2M[]; if (isDefinedAndNotNull(resources)) { const checkedResource = resources.filter(resource => resource[type]); return checkedResource.length !== 0 && checkedResource.length !== resources.length; @@ -190,7 +191,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor } getChecked = (instance: AbstractControl, type: string): boolean => { - const resources = instance.get('resources').value as ResourceLwM2M[]; + const resources = instance.get(RESOURCES).value as ResourceLwM2M[]; return isDefinedAndNotNull(resources) && resources.every(resource => resource[type]); } @@ -239,10 +240,10 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor } private updateInstancesIds = (data: Lwm2mObjectAddInstancesData): void => { - const objectLwM2MFormGroup = (this.observeAttrTelemetryFormGroup.get('clientLwM2M') as FormArray).controls + const objectLwM2MFormGroup = (this.observeAttrTelemetryFormGroup.get(CLIENT_LWM2M) as FormArray).controls .find(e => e.value.id === data.objectId) as FormGroup; const instancesArray = objectLwM2MFormGroup.value.instances as Instance []; - const instancesFormArray = objectLwM2MFormGroup.get('instances') as FormArray; + const instancesFormArray = objectLwM2MFormGroup.get(INSTANCES) as FormArray; const instance0 = deepClone(instancesFormArray.at(0).value as Instance); instance0.resources.forEach(r => { r.attribute = false; diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/profile-config.models.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/profile-config.models.ts index 583cc72a44..05a4e42d2f 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/profile-config.models.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/profile-config.models.ts @@ -16,7 +16,6 @@ import { JsonObject } from '@angular/compiler-cli/ngcc/src/packages/entry_point'; -export const ID = 'id'; export const INSTANCES = 'instances'; export const RESOURCES = 'resources'; export const OBSERVE_ATTR_TELEMETRY = 'observeAttrTelemetry'; @@ -24,6 +23,7 @@ export const OBSERVE = 'observe'; export const ATTRIBUTE = 'attribute'; export const TELEMETRY = 'telemetry'; export const KEY_NAME = 'keyName'; +export const CLIENT_LWM2M = 'clientLwM2M'; export const DEFAULT_ID_SERVER = 123; export const DEFAULT_ID_BOOTSTRAP = 111; export const DEFAULT_HOST_NAME = 'localhost'; @@ -58,6 +58,11 @@ export const SECURITY_CONFIG_MODE_NAMES = new Map( ] ); +export interface ModelValue { + objectIds: number[] | null, + objectsList: ObjectLwM2M[] +} + export interface BootstrapServersSecurityConfig { shortId: number; lifetime: number; From 00e1ed3aa8004e34b69df35782939ec88266ad6d Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Fri, 29 Jan 2021 13:33:30 +0200 Subject: [PATCH 097/249] More tests for Deduplication Executor --- .../utils/EventDeduplicationExecutor.java | 4 +- .../util/EventDeduplicationExecutorTest.java | 40 ++++++++++++++++++- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/utils/EventDeduplicationExecutor.java b/application/src/main/java/org/thingsboard/server/utils/EventDeduplicationExecutor.java index 1c67868740..4ce0d2f3d5 100644 --- a/application/src/main/java/org/thingsboard/server/utils/EventDeduplicationExecutor.java +++ b/application/src/main/java/org/thingsboard/server/utils/EventDeduplicationExecutor.java @@ -56,14 +56,14 @@ public class EventDeduplicationExecutor

{ log.info("[{}] Executing task: {}", name, params); function.accept(params); } catch (Throwable e) { - log.warn("Failed to process task with parameters: {}", params, e); + log.warn("[{}] Failed to process task with parameters: {}", name, params, e); throw e; } finally { unlockAndProcessIfAny(); } }); } catch (Throwable e) { - log.warn("Failed to submit task with parameters: {}", params, e); + log.warn("[{}] Failed to submit task with parameters: {}", name, params, e); unlockAndProcessIfAny(); throw e; } diff --git a/application/src/test/java/org/thingsboard/server/util/EventDeduplicationExecutorTest.java b/application/src/test/java/org/thingsboard/server/util/EventDeduplicationExecutorTest.java index 26718b6624..c58f44e2eb 100644 --- a/application/src/test/java/org/thingsboard/server/util/EventDeduplicationExecutorTest.java +++ b/application/src/test/java/org/thingsboard/server/util/EventDeduplicationExecutorTest.java @@ -41,15 +41,24 @@ public class EventDeduplicationExecutorTest { periodicFlow(MoreExecutors.newDirectExecutorService()); } + @Test + public void testExceptionFlowSameThread() throws InterruptedException { + exceptionFlow(MoreExecutors.newDirectExecutorService()); + } @Test public void testSimpleFlowSingleThread() throws InterruptedException { - simpleFlow(Executors.newFixedThreadPool(1)); + simpleFlow(Executors.newSingleThreadExecutor()); } @Test public void testPeriodicFlowSingleThread() throws InterruptedException { - periodicFlow(Executors.newFixedThreadPool(1)); + periodicFlow(Executors.newSingleThreadExecutor()); + } + + @Test + public void testExceptionFlowSingleThread() throws InterruptedException { + exceptionFlow(Executors.newSingleThreadExecutor()); } @Test @@ -62,6 +71,11 @@ public class EventDeduplicationExecutorTest { periodicFlow(Executors.newFixedThreadPool(3)); } + @Test + public void testExceptionFlowMultiThread() throws InterruptedException { + exceptionFlow(Executors.newFixedThreadPool(3)); + } + private void simpleFlow(ExecutorService executorService) throws InterruptedException { try { Consumer function = Mockito.spy(StringConsumer.class); @@ -105,6 +119,28 @@ public class EventDeduplicationExecutorTest { } } + private void exceptionFlow(ExecutorService executorService) throws InterruptedException { + try { + Consumer function = Mockito.spy(StringConsumer.class); + EventDeduplicationExecutor executor = new EventDeduplicationExecutor<>(EventDeduplicationExecutorTest.class.getSimpleName(), executorService, function); + + String params1 = "params1"; + String params2 = "params2"; + String params3 = "params3"; + + Mockito.doThrow(new RuntimeException()).when(function).accept("params1"); + executor.submit(params1); + executor.submit(params2); + Thread.sleep(500); + executor.submit(params3); + Thread.sleep(500); + Mockito.verify(function).accept(params2); + Mockito.verify(function).accept(params3); + } finally { + executorService.shutdownNow(); + } + } + public static class StringConsumer implements Consumer { @Override public void accept(String s) { From 33928d41358a12bdeed1a9ac9e338fed63d51bd4 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Fri, 29 Jan 2021 14:00:00 +0200 Subject: [PATCH 098/249] Fix NPE in Rest API Call rule node --- .../rule/engine/rest/TbRestApiCallNodeConfiguration.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbRestApiCallNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbRestApiCallNodeConfiguration.java index 40b79163b8..b3eb982287 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbRestApiCallNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbRestApiCallNodeConfiguration.java @@ -61,4 +61,12 @@ public class TbRestApiCallNodeConfiguration implements NodeConfiguration Date: Fri, 29 Jan 2021 14:02:48 +0200 Subject: [PATCH 099/249] Refactoring code to dynamic color point in trip-animation widget --- .../components/widget/lib/maps/leaflet-map.ts | 4 +-- .../components/widget/lib/maps/map-widget2.ts | 2 +- .../components/widget/lib/maps/schemes.ts | 30 +++++++++---------- .../trip-animation.component.ts | 4 +-- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts index 67f44cd941..9da5e679f4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts @@ -626,11 +626,11 @@ export default abstract class LeafletMap { } this.points = new FeatureGroup(); } - let pointColor = this.options.pointColor; + let pointColor = this.options.pointColor; for (const pointsList of pointsData) { pointsList.filter(pdata => !!this.convertPosition(pdata)).forEach(data => { if (this.options.useColorPointFunction) { - pointColor = safeExecute(this.options.colorPointFunction,[data, pointsData, data.dsIndex]); + pointColor = safeExecute(this.options.colorPointFunction, [data, pointsData, data.dsIndex]); } const point = L.circleMarker(this.convertPosition(data), { color: pointColor, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts index 393ea747a0..3a48e8e20f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts @@ -301,7 +301,7 @@ export class MapWidgetController implements MapWidgetInterface { labelFunction: parseFunction(settings.labelFunction, functionParams), tooltipFunction: parseFunction(settings.tooltipFunction, functionParams), colorFunction: parseFunction(settings.colorFunction, functionParams), - colorPointFunction: parseFunction(settings.colorPointFunction, functionParams), + colorPointFunction: parseFunction(settings.colorPointFunction, functionParams), polygonColorFunction: parseFunction(settings.polygonColorFunction, functionParams), polygonTooltipFunction: parseFunction(settings.polygonTooltipFunction, functionParams), markerImageFunction: parseFunction(settings.markerImageFunction, ['data', 'images', 'dsData', 'dsIndex']), diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts index 3c8b7f031c..b00e01404a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts @@ -871,6 +871,15 @@ export const pointSchema = title: 'Point color', type: 'string' }, + useColorPointFunction: { + title: 'Use color point function', + type: 'boolean', + default: false + }, + colorPointFunction: { + title: 'Color point function: f(data, dsData, dsIndex)', + type: 'string' + }, pointSize: { title: 'Point size (px)', type: 'number', @@ -899,6 +908,11 @@ export const pointSchema = key: 'pointColor', type: 'color' }, + 'useColorPointFunction', + { + key: 'colorPointFunction', + type: 'javascript' + }, 'pointSize', 'usePointAsAnchor', { @@ -1036,15 +1050,6 @@ export const tripAnimationSchema = { title: 'Custom marker image', type: 'string' }, - useColorPointFunction: { - title: 'Use color point function', - type: 'boolean', - default: false - }, - colorPointFunction: { - title: 'Color point function: f(data, dsData, dsIndex)', - type: 'string' - }, markerImageSize: { title: 'Custom marker image size (px)', type: 'number', @@ -1090,12 +1095,7 @@ export const tripAnimationSchema = { }, 'useTooltipFunction', { key: 'tooltipFunction', type: 'javascript' - }, 'autocloseTooltip', 'useColorPointFunction', - { - key: 'colorPointFunction', - type: 'javascript' - }, - { + }, 'autocloseTooltip', { key: 'markerImage', type: 'image' }, 'markerImageSize', 'rotationAngle', 'useMarkerImageFunction', diff --git a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts index 319a1139ed..2581da88ad 100644 --- a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts @@ -112,7 +112,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy this.settings.pointAsAnchorFunction = parseFunction(this.settings.pointAsAnchorFunction, ['data', 'dsData', 'dsIndex']); this.settings.tooltipFunction = parseFunction(this.settings.tooltipFunction, ['data', 'dsData', 'dsIndex']); this.settings.labelFunction = parseFunction(this.settings.labelFunction, ['data', 'dsData', 'dsIndex']); - this.settings.colorPointFunction = parseFunction(this.settings.colorPointFunction, ['data', 'dsData', 'dsIndex']); + this.settings.colorPointFunction = parseFunction(this.settings.colorPointFunction, ['data', 'dsData', 'dsIndex']); this.normalizationStep = this.settings.normalizationStep; const subscription = this.ctx.defaultSubscription; subscription.callbacks.onDataUpdated = () => { @@ -179,7 +179,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy if (this.settings.showPolygon) { this.mapWidget.map.updatePolygons(this.interpolatedTimeData); } - if (this.settings.showPoints || this.settings.useColorPointFunction) { + if (this.settings.showPoints) { this.mapWidget.map.updatePoints(formattedInterpolatedTimeData.map(ds => _.union(ds)), this.calcTooltip); } this.mapWidget.map.updateMarkers(currentPosition, true, (trip) => { From a3d2eb4c4e69da5e7490a18b696e835a7c915ceb Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Fri, 29 Jan 2021 15:05:31 +0200 Subject: [PATCH 100/249] Fix NPE in entity data subscription --- .../subscription/DefaultTbEntityDataSubscriptionService.java | 4 +++- .../server/service/subscription/TbAbstractDataSubCtx.java | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbEntityDataSubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbEntityDataSubscriptionService.java index 124823a6ad..1b455085eb 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbEntityDataSubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbEntityDataSubscriptionService.java @@ -302,7 +302,9 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc Map sessionSubs = subscriptionsBySessionId.computeIfAbsent(sessionRef.getSessionId(), k -> new HashMap<>()); TbEntityDataSubCtx ctx = new TbEntityDataSubCtx(serviceId, wsService, entityService, localSubscriptionService, attributesService, stats, sessionRef, cmd.getCmdId(), maxEntitiesPerDataSubscription); - ctx.setAndResolveQuery(cmd.getQuery()); + if (cmd.getQuery() != null) { + ctx.setAndResolveQuery(cmd.getQuery()); + } sessionSubs.put(cmd.getCmdId(), ctx); return ctx; } diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/TbAbstractDataSubCtx.java b/application/src/main/java/org/thingsboard/server/service/subscription/TbAbstractDataSubCtx.java index 8b0f5b3a94..9b03e40f1e 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/TbAbstractDataSubCtx.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/TbAbstractDataSubCtx.java @@ -107,7 +107,7 @@ public abstract class TbAbstractDataSubCtx Date: Mon, 1 Feb 2021 12:05:07 +0100 Subject: [PATCH 102/249] Sync spanish translations, add device profile, tenant profiles, oauth, API usage --- .../assets/locale/locale.constant-es_ES.json | 803 +++++++++++++++--- 1 file changed, 698 insertions(+), 105 deletions(-) diff --git a/ui-ngx/src/assets/locale/locale.constant-es_ES.json b/ui-ngx/src/assets/locale/locale.constant-es_ES.json index 91286c0c3f..3162786211 100644 --- a/ui-ngx/src/assets/locale/locale.constant-es_ES.json +++ b/ui-ngx/src/assets/locale/locale.constant-es_ES.json @@ -4,9 +4,11 @@ "unauthorized-access": "Acceso no autorizado", "unauthorized-access-text": "Debes iniciar sesión para tener acceso a este recurso!", "access-forbidden": "Acceso Prohibido", - "access-forbidden-text": "No tienes derechos para acceder a esta ubicación!
Intenta iniciar sesión con otro usuario si todavía quieres acceder a esta ubicación.", + "access-forbidden-text": "No tienes suficientes derechos para acceder a esta ubicación!
Intenta iniciar sesión con otro usuario si todavía quieres acceder a esta ubicación.", "refresh-token-expired": "La sesión ha expirado", - "refresh-token-failed": "No se puede actualizar la sesión" + "refresh-token-failed": "No se puede actualizar la sesión", + "permission-denied": "Permiso Denegado", + "permission-denied-text": "No tienes suficientes derechos para realizar esta operación!" }, "action": { "activate": "Activar", @@ -21,6 +23,7 @@ "no": "No", "update": "Actualizar", "remove": "Eliminar", + "select": "Seleccionar", "search": "Buscar", "clear-search": "Borrar búsqueda", "assign": "Asignar", @@ -49,13 +52,16 @@ "import": "Importar", "export": "Exportar", "share-via": "Compartir vía {{provider}}", - "discard-changes": "Cancelar los cambios", "continue": "Continuar", - "download": "Descargar" + "discard-changes": "Cancelar cambios", + "download": "Descargar", + "next-with-label": "Siguiente: {{label}}", + "read-more": "Leer más", + "hide": "Ocultar" }, "aggregation": { - "aggregation": "Agregación", - "function": "Función de Agregación", + "aggregation": "Agrupación", + "function": "Función de Agrupación", "limit": "Valores Max", "group-interval": "Intervalo de agrupación", "min": "Min", @@ -74,6 +80,8 @@ "test-mail-sent": "Mail de prueba enviado correctamente!", "base-url": "URL Base", "base-url-required": "URL Base requerida.", + "prohibit-different-url": "Prohibir el uso de hostname en cabeceras de request del cliente", + "prohibit-different-url-hint": "Este ajuste debe ser activado en entornos de producción. Puede causar fallos de seguridad si está desactivado", "mail-from": "Mail Desde", "mail-from-required": "Mail Desde requerido.", "smtp-protocol": "Protocolo SMTP", @@ -87,9 +95,44 @@ "timeout-invalid": "No parece un Timeout valido.", "enable-tls": "Habilitar TLS", "tls-version": "Versión TLS", + "enable-proxy": "Habilitar proxy", + "proxy-host": "Host proxy", + "proxy-host-required": "Se requiere host Proxy.", + "proxy-port": "Puerto proxy", + "proxy-port-required": "Se requiere puerto proxy.", + "proxy-port-range": "El puerto proxy debe estar en un rango de 1 a 65535.", + "proxy-user": "Usuario proxy", + "proxy-password": "Contraseña proxy", "send-test-mail": "Enviar correo de prueba", - "password-policy": "Política de contraseñas", + "sms-provider": "Proveedor SMS", + "sms-provider-settings": "Ajustes proveedor SMS", + "sms-provider-type": "Tipo de proveedor SMS", + "sms-provider-type-required": "Se requiere proveedor SMS.", + "sms-provider-type-aws-sns": "Amazon SNS", + "sms-provider-type-twilio": "Twilio", + "aws-access-key-id": "AWS Access Key ID", + "aws-access-key-id-required": "Se requiere AWS Access Key ID", + "aws-secret-access-key": "AWS Secret Access Key", + "aws-secret-access-key-required": "Se requere AWS Secret Access Key", + "aws-region": "Región AWS", + "aws-region-required": "Se requere región AWS", + "number-from": "Nº de teléfono Origen", + "number-from-required": "Se requere Nº de teléfono origen.", + "number-to": "Nº de teléfono de destino", + "number-to-required": "Se requere Nº de teléfono de destino.", + "phone-number-hint": "Nº de teléfono en formato E.164, ex. +19995550123", + "phone-number-pattern": "Nº Inválido. Debe estar en formato E.164, ex. +19995550123.", + "sms-message": "Mensaje SMS", + "sms-message-required": "Se requeriere mensaje SMS.", + "sms-message-max-length": "Los SMS no pueden ser más largos de 1600 caracteres", + "twilio-account-sid": "SID de cuenta Twilio", + "twilio-account-sid-required": "Se requere SID de cuenta Twilio", + "twilio-account-token": "Token de cuenta Twilio", + "twilio-account-token-required": "Se requiere Token Twilio", + "send-test-sms": "Enviar SMS de prueba", + "test-sms-sent": "SMS enviado con éxito!", "security-settings": "Configuraciones de seguridad", + "password-policy": "Política de contraseñas", "minimum-password-length": "Longitud mínima de contraseña", "minimum-password-length-required": "Se requiere una longitud mínima de contraseña", "minimum-password-length-range": "La longitud mínima de la contraseña debe estar en un rango de 5 a 50", @@ -108,8 +151,74 @@ "general-policy": "Política general", "max-failed-login-attempts": "Número máximo de intentos fallidos de inicio de sesión, antes de que la cuenta esté bloqueada", "minimum-max-failed-login-attempts-range": "El número máximo de intentos fallidos de inicio de sesión no puede ser negativo", - "user-lockout-notification-email": "En caso de bloqueo de la cuenta del usuario, envíe una notificación por correo electrónico" - }, + "user-lockout-notification-email": "En caso de bloqueo de la cuenta del usuario, envíe una notificación por correo electrónico", + "domain-name": "Nombre de dominio", + "domain-name-unique": "El nombre de dominio y protocolo debe ser único.", + "error-verification-url": "Un nombre de dominio no debe contener símbolos '/' y ':'. Ejemplo: thingsboard.io", + "oauth2": { + "access-token-uri": "URI Access token", + "access-token-uri-required": "Se requere URI Access token.", + "activate-user": "Activar usuario", + "add-domain": "Añadir dominio", + "delete-domain": "Borrar dominio", + "add-provider": "Añadir proveedor", + "delete-provider": "Borrar proveedor", + "allow-user-creation": "Permitir creación de usuario", + "always-fullscreen": "Siempre pantalla completa", + "authorization-uri": "URI Autorización", + "authorization-uri-required": "Se requiere URI de Autorización.", + "client-authentication-method": "Método de autenticación", + "client-id": "ID Cliente", + "client-id-required": "Se requere ID Cliente.", + "client-secret": "Secreto de Cliente", + "client-secret-required": "Se requiere Secreto de Cliente.", + "custom-setting": "Ajustes personalizados", + "customer-name-pattern": "Patrón nombre de cliente", + "default-dashboard-name": "Nombre de panel por defecto", + "delete-domain-text": "Atención, tras la confirmación el dominio y todos los datos del proveedor no estarán disponibles.", + "delete-domain-title": "Eliminar los ajustes del dominio '{{domainName}}'?", + "delete-registration-text": "Atención, tras la confirmación los datos del proveedor no estarán disponibles.", + "delete-registration-title": "Eliminar el proveedor '{{name}}'?", + "email-attribute-key": "Clave de atributos email", + "email-attribute-key-required": "Se requiere clave de atributos de email.", + "first-name-attribute-key": "Clave de atributos de nombre", + "general": "General", + "jwk-set-uri": "URI web key JSON", + "last-name-attribute-key": "Clave de atributos de apellido", + "login-button-icon": "Icono de botón login", + "login-button-label": "Etiqueta de proveedor", + "login-button-label-placeholder": "Login con $(Provider label)", + "login-button-label-required": "Clave de etiqueta requerida.", + "login-provider": "Proveedor de login", + "mapper": "Mapeador", + "new-domain": "Nuevo dominio", + "oauth2": "OAuth2", + "redirect-uri-template": "Plantilla de redirección URI", + "copy-redirect-uri": "Copiar URI de redirección", + "registration-id": "ID de registro", + "registration-id-required": "Se requiere ID de registro.", + "registration-id-unique": "El ID de registro debe ser único en el sistema.", + "scope": "Alcance", + "scope-required": "Se requiere alcance.", + "tenant-name-pattern": "Patrón de nombre de propietario", + "tenant-name-pattern-required": "Se requiere patrón de nombre de propietario.", + "tenant-name-strategy": "Estrategia de Nombre de Propietario", + "type": "Tipo de mapeador", + "uri-pattern-error": "Formato de URI inválido.", + "url": "URL", + "url-pattern": "Formato URL inválido.", + "url-required": "Se requiere URL.", + "user-info-uri": "URI Información de usuario", + "user-info-uri-required": "Se requiere URI de información usuario.", + "user-name-attribute-name": "Clave de atributos de nombre de usuario", + "user-name-attribute-name-required": "Se requiere clave de atributos de nombre de usuario", + "protocol": "Protocolo", + "domain-schema-http": "HTTP", + "domain-schema-https": "HTTPS", + "domain-schema-mixed": "HTTP+HTTPS", + "enable": "Activar ajustes OAuth2" + } + }, "alarm": { "alarm": "Alarma", "alarms": "Alarmas", @@ -117,6 +226,8 @@ "no-alarms-matching": "No se han encontrado alarmas coincidentes con '{{entity}}' .", "alarm-required": "Alarma requerida", "alarm-status": "Estado de Alarma", + "alarm-status-list": "Lista de estados de Alarmas", + "any-status": "Cualquier estado", "search-status": { "ANY": "Todas", "ACTIVE": "Activas", @@ -143,6 +254,8 @@ "end-time": "Hora fin", "ack-time": "Hora de reconocimiento", "clear-time": "Hora de normalización", + "alarm-severity-list": "Lista de gravedad de alarmas", + "any-severity": "Cualquier gravedad", "severity-critical": "Crítica", "severity-major": "Mayor", "severity-minor": "Menor", @@ -158,19 +271,23 @@ "min-polling-interval-message": "El ciclo debe ser por lo menos de 1 segundo.", "aknowledge-alarms-title": "Reconocer { count, plural, 1 {1 alarma} other {# alarmas} }", "aknowledge-alarms-text": "Estas seguro de reconocer { count, plural, 1 {1 alarma} other {# alarmas} }?", - "aknowledge-alarm-title": "Recononcer Alarma", + "aknowledge-alarm-title": "Recononcer Alarma", "aknowledge-alarm-text": "Estas seguro de reconocer Alarma?", "clear-alarms-title": "Normalizar { count, plural, 1 {1 alarma} other {# alarmas} }", - "clear-alarms-text": "Estás seguro de limpiar { count, plural, 1 {1 alarma} other {# alarmas} }?", - "clear-alarm-title": "Limpiar Alarma", - "clear-alarm-text": "Estás seguro de limpiar Alarma?", - "alarm-status-filter": "Filtro de Alarmas", + "clear-alarms-text": "Limpiar { count, plural, 1 {1 alarma} other {# alarmas} }?", + "clear-alarm-title": "Limpiar Alarma", + "clear-alarm-text": "Limpiar Alarma?", + "alarm-status-filter": "Filtro de estados de Alarmas", + "alarm-filter": "Filtro de Alarmas", "max-count-load": "Número máximo de alarmas a cargar (0 - ilimitado)", "max-count-load-required": "Se requiere número máximo de alarmas.", "max-count-load-error-min": "El valor mínimo es 0.", "fetch-size": "Tamaño de búsqueda (Fetch)", "fetch-size-required": "Se requiere tamaño de búsqueda.", - "fetch-size-error-min": "El valor mínimo es 10." + "fetch-size-error-min": "El valor mínimo es 10.", + "alarm-type-list": "Lista de tipos de alarma", + "any-type": "Cualquier tipo", + "search-propagated-alarms": "Buscar alarmas propagadas" }, "alias": { "add": "Añadir alias", @@ -200,6 +317,7 @@ "filter-type-device-search-query-description": "Dispositivos con tipos {{deviceTypes}} que tienen {{relationType}} relación {{direction}} {{rootEntity}}", "filter-type-entity-view-search-query": "Consulta de búsqueda de vista de entidad", "filter-type-entity-view-search-query-description": "Vistas de entidad con tipos {{entityViewTypes}} que tienen tipo de relación {{relationType}} con dirección {{direction}} {{rootEntity}}", + "filter-type-apiUsageState": "Uso de API", "entity-filter": "Filtro por entidad", "resolve-multiple": "Tomar como múltiples entidades", "filter-type": "Filtro por tipo", @@ -259,19 +377,19 @@ "unassign-assets": "Cancelar asignación de activo", "unassign-assets-action-title": "Cancelar asignación de { count, plural, 1 {1 activo} other {# activos} } del cliente", "assign-new-asset": "Asignar nuevo activo", - "delete-asset-title": "Estás seguro de borrar el activo '{{assetName}}'?", + "delete-asset-title": "Eliminar el activo '{{assetName}}'?", "delete-asset-text": "Atención, tras la confirmación el activo y sus datos serán borrados e irrecuperables.", - "delete-assets-title": "Estás seguro de borrar los activos { count, plural, 1 {1 activo} other {# activos} }?", + "delete-assets-title": "Eliminar los activos { count, plural, 1 {1 activo} other {# activos} }?", "delete-assets-action-title": "Borrar { count, plural, 1 {1 activo} other {# activos} }", "delete-assets-text": "Atención, tras la confirmación todos los activos seleccionados y sus datos serán borrados e irrecuperables.", - "make-public-asset-title": "Estás seguro de hacer el activo '{{assetName}}' público?", + "make-public-asset-title": "Hacer el activo '{{assetName}}' público?", "make-public-asset-text": "Tras la confirmación, el activo y sus datos se harán públicos y accesibles por otros.", - "make-private-asset-title": "Estás seguro de hacer el activo '{{assetName}}' privado?", + "make-private-asset-title": "Hacer el activo '{{assetName}}' privado?", "make-private-asset-text": "Tras la confirmación, el activo y sus datos se harán privados y no serán accesibles por otros.", - "unassign-asset-title": "Estás seguro de cancelar la asignación del activo '{{assetName}}'?", + "unassign-asset-title": "Cancelar la asignación del activo '{{assetName}}'?", "unassign-asset-text": "Tras la confirmación, el activo será desasignado y no será accesible por el cliente.", "unassign-asset": "Cancelar asignación de activo", - "unassign-assets-title": "Estás seguro de cancelar las asignaciones { count, plural, 1 {1 activo} other {# activos} }?", + "unassign-assets-title": "Cancelar las asignaciones { count, plural, 1 {1 activo} other {# activos} }?", "unassign-assets-text": "Tras la confirmación todos los activos seleccionados serán desasignados y no serán accesibles por el cliente.", "copyId": "Copiar ID de activo", "idCopiedMessage": "El ID ha sido copiado al portapapeles", @@ -281,6 +399,8 @@ "name-starts-with": "El nombre de activo comienza con", "import": "Importar activos", "asset-file": "Archivo del activo", + "search": "Buscar activos", + "selected-assets": "{ count, plural, 1 {1 activo} other {# activos} } seleccionados", "label": "Etiqueta" }, "attribute": { @@ -297,7 +417,7 @@ "key-required": "Clave del atributo requerida.", "value": "Valor", "value-required": "Valor del atributo requerido.", - "delete-attributes-title": "¿Estás seguro que quieres eliminar { count, plural, 1 {1 atributo} other {# atributos} }?", + "delete-attributes-title": "¿Eliminar { count, plural, 1 {1 atributo} other {# atributos} }?", "delete-attributes-text": "Atención, tras la confirmación el atributo será eliminado, y la información relacionada será irrecuperable.", "delete-attributes": "Borrar atributo", "enter-attribute-value": "Ingresar valor del atributo", @@ -308,7 +428,62 @@ "add-to-dashboard": "Agregar al Panel", "add-widget-to-dashboard": "Agregar widget al Panel", "selected-attributes": "{ count, plural, 1 {1 atributo} other {# atributos} } seleccionados", - "selected-telemetry": "{ count, plural, 1 {1 telemetría} other {# telemetrías} } seleccionadas" + "selected-telemetry": "{ count, plural, 1 {1 telemetría} other {# telemetrías} } seleccionadas", + "no-attributes-text": "No se encontró ningún atributo", + "no-telemetry-text": "No se encontró ninguna telemetría" + }, + "api-usage": { + "api-usage": "Uso de API", + "data-points": "Puntos de datos", + "data-points-storage-days": "Días de grabación de puntos de datos", + "email": "Email", + "email-messages": "Mensajes de Email", + "email-messages-daily-activity": "Actividad diaria de Emails", + "email-messages-hourly-activity": "Actividad horaria de Emails", + "email-messages-monthly-activity": "Actividad mensual de Emails", + "exceptions": "Excepciones", + "executions": "Ejecuciones", + "javascript": "JavaScript", + "javascript-executions": "Ejecuciones JavaScript", + "javascript-functions": "Funciones JavaScript", + "javascript-functions-daily-activity": "Actividad diaria de funciones JavaScript", + "javascript-functions-hourly-activity": "Actividad horaria de funciones JavaScript", + "javascript-functions-monthly-activity": "Actividad mensual de funciones JavaScript", + "latest-error": "Último error", + "messages": "Mensajes", + "permanent-failures": "${entityName} Fallos permanentes", + "permanent-timeouts": "${entityName} Timeouts permanentes", + "processing-failures": "${entityName} Fallos de procesamiento", + "processing-failures-and-timeouts": "Fallos de procesamiento y timeouts", + "processing-timeouts": "${entityName} Timeouts de procesamiento", + "queue-stats": "Estadísticas de colas", + "rule-chain": "Cadena de reglas", + "rule-engine": "Motor de reglas", + "rule-engine-daily-activity": "Actividad diaria de motor de reglas", + "rule-engine-executions": "Ejecuciones de motor de reglas", + "rule-engine-hourly-activity": "Actividad horaria de motor de reglas", + "rule-engine-monthly-activity": "Actividad mensual de motor de reglas", + "rule-engine-statistics": "Estadisticas del motor de reglas", + "rule-node": "Nodo de reglas", + "sms": "SMS", + "sms-messages": "Mensajes SMS", + "sms-messages-daily-activity": "Actividad diaria de mensajes SMS", + "sms-messages-hourly-activity": "Actividad horaria de mensajes SMS", + "sms-messages-monthly-activity": "Actividad mensual de mensajes SMS", + "successful": "${entityName} Exitoso", + "telemetry": "Telemetría", + "telemetry-persistence": "Persistencia de telemetría", + "telemetry-persistence-daily-activity": "Actividad diaria de persistencia de telemetría", + "telemetry-persistence-hourly-activity": "Actividad horaria de persistencia de telemetría", + "telemetry-persistence-monthly-activity": "Actividad mensual de persistencia de telemetría", + "transport": "Transporte", + "transport-daily-activity": "Actividad diaria de transporte", + "transport-data-points": "Puntos de datos de transporte", + "transport-hourly-activity": "Actividad horaria de transporte", + "transport-messages": "Mensajes de transporte", + "transport-monthly-activity": "Actividad mensual de transporte", + "view-details": "Ver detalles", + "view-statistics": "Ver estadísticas" }, "audit-log": { "audit": "Auditoría", @@ -348,11 +523,17 @@ "action-data": "Datos de acción", "failure-details": "Detalles del error", "search": "Buscar registros de auditoría", - "clear-search": "Borrar búsqueda" + "clear-search": "Borrar búsqueda", + "type-assigned-from-tenant": "Asignado desde el administrador", + "type-assigned-to-tenant": "Asignado al administrador", + "type-provision-success": "Dispositivo aprovisionado", + "type-provision-failure": "Aprovisionamiento fallido", + "type-timeseries-updated": "Telemetría actualizada", + "type-timeseries-deleted": "Telemetría borrada" }, "confirm-on-exit": { - "message": "Tienes cambios sin guardar. ¿Estás seguro que quieres abandonar la página?", - "html-message": "Tienes cambios sin guardar.
¿Estás seguro que quieres abandonar la página?", + "message": "Tienes cambios sin guardar. ¿Abandonar la página?", + "html-message": "Tienes cambios sin guardar.
¿Abandonar la página?", "title": "Cambios sin guardar" }, "contact": { @@ -372,7 +553,9 @@ "password": "Contraseña", "enter-username": "Introduce el nombre de usuario.", "enter-password": "Introduce la contraseña", - "enter-search": "Introduce búsqueda" + "enter-search": "Introduce búsqueda", + "created-time": "Fecha de creación", + "loading": "Cargando..." }, "content-type": { "json": "Json", @@ -404,9 +587,9 @@ "add-customer-text": "Agregar nuevo cliente", "no-customers-text": "No se encontraron clientes", "customer-details": "Detalles del cliente", - "delete-customer-title": "¿Estás seguro que quieres eliminar el cliente '{{customerTitle}}'?", + "delete-customer-title": "¿Eliminar el cliente '{{customerTitle}}'?", "delete-customer-text": "Atención, tras la confirmación el cliente será eliminado y toda la información relacionada será irrecuperable.", - "delete-customers-title": "¿Estás seguro que quieres eliminar { count, plural, 1 {1 cliente} other {# clientes} }?", + "delete-customers-title": "¿Eliminar { count, plural, 1 {1 cliente} other {# clientes} }?", "delete-customers-action-title": "Borrar { count, plural, 1 {1 cliente} other {# clientes} }", "delete-customers-text": "Atención, tras la confirmación todos los clientes seleccionados serán eliminados y su información relacionada será irrecuperable.", "manage-users": "Gestionar usuarios", @@ -425,7 +608,9 @@ "customer-required": "Cliente requerido", "select-default-customer": "Seleccionar cliente por defecto", "default-customer": "Cliente por defecto", - "default-customer-required": "Se requiere cliente por defecto para realizar debug a nivel de propietario" + "default-customer-required": "Se requiere cliente por defecto para realizar debu a nivel de propietario", + "search": "Buscar clientes", + "selected-customers": "{ count, plural, 1 {1 cliente} other {# clientes} } seleccionados" }, "datetime": { "date-from": "Fecha desde", @@ -471,20 +656,20 @@ "delete-dashboards": "Eliminar paneles", "unassign-dashboards": "Desasignar paneles", "unassign-dashboards-action-title": "Desasignar { count, plural, 1 {1 paneles} other {# paneles} } del cliente", - "delete-dashboard-title": "¿Estás seguro que quieres eliminar el panel '{{dashboardTitle}}'?", + "delete-dashboard-title": "¿Eliminar el panel '{{dashboardTitle}}'?", "delete-dashboard-text": "Atención, el panel seleccionado será eliminado y la información relacionada sera irrecuperable.", - "delete-dashboards-title": "¿Estás seguro que quieres eliminar { count, plural, 1 {1 panel} other {# paneles} }?", + "delete-dashboards-title": "¿Eliminar { count, plural, 1 {1 panel} other {# paneles} }?", "delete-dashboards-action-title": "Eliminar { count, plural, 1 {1 panel} other {# paneles} }", "delete-dashboards-text": "Atención, los paneles seleccionados serán eliminados y la información relacionada será irrecuperable.", - "unassign-dashboard-title": "¿Estás seguro que quieres desasignar el panel '{{dashboardTitle}}'?", + "unassign-dashboard-title": "¿Desasignar el panel '{{dashboardTitle}}'?", "unassign-dashboard-text": "Tras la confirmación, el panel será desasignado y no podrá ser accesible por el cliente.", "unassign-dashboard": "Desasignar panel", - "unassign-dashboards-title": "¿Estás seguro que quieres desasignar { count, plural, 1 {1 panel} other {# paneles} }?", + "unassign-dashboards-title": "¿Desasignar { count, plural, 1 {1 panel} other {# paneles} }?", "unassign-dashboards-text": "Atención, tras la confirmación los paneles seleccionados serán desasignados y no podrán ser accesibles por el cliente.", "public-dashboard-title": "El panel ahora es público", "public-dashboard-text": "Tu panel {{dashboardTitle}} es ahora público y podrá ser accedido desde: aquí:", "public-dashboard-notice": "Nota: No olvides hacer públicos los dispositivos relacionados para acceder a sus datos.", - "make-private-dashboard-title": "¿Estás seguro que quieres hacer el panel '{{dashboardTitle}}' privado?", + "make-private-dashboard-title": "¿Hacer el panel '{{dashboardTitle}}' privado?", "make-private-dashboard-text": "Tras la confirmación, el panel será privado y no podrá ser accesible por otros.", "make-private-dashboard": "Hacer panel privado", "socialshare-text": "'{{dashboardTitle}}' powered by ThingsBoard", @@ -508,6 +693,9 @@ "min-columns-count-message": "Solo se permite un número mínimo de 10 columnas.", "max-columns-count-message": "Solo se permite un número máximo de 1000 columnas.", "widgets-margins": "Margen entre widgets", + "margin-required": "Valor de margen requerido.", + "min-margin-message": "0 es el valor de margen mínimo permitido.", + "max-margin-message": "50 es el valor de margen máximo permitido.", "horizontal-margin": "Margen horizontal", "horizontal-margin-required": "Margen horizontal requerido.", "min-horizontal-margin-message": "Solo se permite margen horizontal mínimo de 0.", @@ -527,6 +715,7 @@ "title-color": "Color del título", "display-dashboards-selection": "Mostrar selección de paneles", "display-entities-selection": "Mostrar selección de entidades", + "display-filters": "Mostrar filtros", "display-dashboard-timewindow": "Mostrar ventana de tiempo", "display-dashboard-export": "Mostrar exportar", "import": "Importar panel", @@ -560,6 +749,7 @@ "edit-state": "Editar estado panel", "delete-state": "Borrar estado panel", "add-state": "Añadir estado panel", + "no-states-text": "No se han encontrado estados", "state": "Estado de panel", "state-name": "Nombre", "state-name-required": "Se requiere nombre del estado.", @@ -568,11 +758,13 @@ "state-id-exists": "Ya existe un ID de estado.", "is-root-state": "Estado raiz(Root)", "delete-state-title": "Borrar estado de panel", - "delete-state-text": "Estás seguro de eliminar el estado de panel con nombre: '{{stateName}}'?", + "delete-state-text": "Eliminar el estado de panel con nombre: '{{stateName}}'?", "show-details": "Mostrar detalles", "hide-details": "Ocultar detalles", "select-state": "Seleccionar estado destino (target state)", - "state-controller": "Controlador de estados" + "state-controller": "Controlador de estados", + "search": "Buscar paneles", + "selected-dashboards": "{ count, plural, 1 {1 panel} other {# paneles} } seleccionados" }, "datakey": { "settings": "Ajustes", @@ -590,6 +782,7 @@ "alarm": "Campos de alarma", "timeseries-required": "Series de tiempo del dispositivo requerido.", "timeseries-or-attributes-required": "Series de tiempo/Atributos requeridos.", + "alarm-fields-timeseries-or-attributes-required": "Se requieren campos de alarma o series de tiempo/atributos.", "maximum-timeseries-or-attributes": "Máximo { count, plural, 1 {1 timeseries/atributo es permitido.} other {# timeseries/atributos son permitidos} }", "alarm-fields-required": "Campos de alarma requeridos.", "function-types": "Tipos de funciones", @@ -607,6 +800,7 @@ "add-datasource-prompt": "Por favor, agrega una fuente de datos" }, "details": { + "details": "Detalles", "edit-mode": "Modo Edición", "edit-json": "Editar JSON", "toggle-edit-mode": "Ir a Modo Edición" @@ -658,20 +852,20 @@ "unassign-devices": "Desasignar dispositivos", "unassign-devices-action-title": "Desasignar { count, plural, 1 {1 dispositivo} other {# dispositivos} } del cliente", "assign-new-device": "Asignar nuevo dispositivo", - "make-public-device-title": "¿Estás seguro que quieres hacer el dispositivo '{{deviceName}}' público?", + "make-public-device-title": "¿Hacer el dispositivo '{{deviceName}}' público?", "make-public-device-text": "Tras la confirmación, el dispositivo y la información relacionada serán públicos y podrá ser accesible por otros.", - "make-private-device-title": "¿Estás seguro que quieres hacer el dispositivo '{{deviceName}}' privado?", + "make-private-device-title": "¿Hacer el dispositivo '{{deviceName}}' privado?", "make-private-device-text": "Tras la confirmación, el dispositivo y la información relacionada serán privados y no podrá ser accesible por otros.", "view-credentials": "Ver credenciales", - "delete-device-title": "¿Estás seguro que quieres eliminar el dispositivo '{{deviceName}}'?", + "delete-device-title": "¿Eliminar el dispositivo '{{deviceName}}'?", "delete-device-text": "Atención, tras la confirmación los dispositivos serán eliminados y la información relacionada será irrecuperable.", - "delete-devices-title": "¿Estás seguro que quieres eliminar { count, plural, 1 {1 dispositivo} other {# dispositivos} }?", + "delete-devices-title": "¿Eliminar { count, plural, 1 {1 dispositivo} other {# dispositivos} }?", "delete-devices-action-title": "Eliminar { count, plural, 1 {1 dispositivo} other {# dispositivos} }", "delete-devices-text": "Atención, tras la confirmación los dispositivos seleccionados serán eliminados y la información relacionada será irrecuperable.", - "unassign-device-title": "¿Estás seguro que quieres desasignar el dispositivo '{{deviceName}}'?", + "unassign-device-title": "¿Desasignar el dispositivo '{{deviceName}}'?", "unassign-device-text": "Tras la confirmación, el dispositivo será desasignado y no podrá ser accesible por el cliente.", "unassign-device": "Desasignar dispositivo", - "unassign-devices-title": "¿Estás seguro que quieres desasignar { count, plural, 1 {1 dispositivo} other {# dispositivos} }?", + "unassign-devices-title": "¿Desasignar { count, plural, 1 {1 dispositivo} other {# dispositivos} }?", "unassign-devices-text": "Tras la confirmación, los dispositivos seleccionados serán desasignados y no podrán ser accedidos por el cliente.", "device-credentials": "Credenciales del dispositivo", "credentials-type": "Tipo de credencial", @@ -680,6 +874,12 @@ "access-token-invalid": "Access token debe tener entre 1 a 20 caracteres.", "rsa-key": "Clave pública RSA", "rsa-key-required": "Clave pública RSA requerida.", + "client-id": "ID Cliente", + "client-id-pattern": "Contiene carácter inválido.", + "user-name": "Nombre Usuario", + "user-name-required": "Se requiere nombre de usuario.", + "client-id-or-user-name-necessary": "El ID Cliente y/o el Nombre de usuario son necesarios", + "password": "Contraseña", "secret": "Secreta", "secret-required": "Secreta requerida.", "device-type": "Tipo de dispositivo", @@ -692,25 +892,191 @@ "device-types": "Tipos de dispositivo", "name": "Nombre", "name-required": "El nombre es requerido.", - "label": "Etiqueta", "description": "Descripción", + "label": "Etiqueta", "events": "Eventos", "details": "Detalles", "copyId": "Copiar ID", "copyAccessToken": "Copiar access token", + "copy-mqtt-authentication": "Copiar credenciales MQTT", "idCopiedMessage": "Id del dispositivo copiado al portapapeles", "accessTokenCopiedMessage": "Access token del dispositivo copiado al portapapeles", + "mqtt-authentication-copied-message": "Los datos de autenticación MQTT se han copiado al portapapeles", "assignedToCustomer": "Asignado al cliente", "unable-delete-device-alias-title": "Imposible eliminar alias del dispositivo", "unable-delete-device-alias-text": "Alias '{{deviceAlias}}' no puede ser eliminado. Esta siendo usado por el(los) widget(s):
{{widgetsList}}", "is-gateway": "Es gateway", + "overwrite-activity-time": "Sobreescribir hora de actividad para el dispositivo conectado", "public": "Público", "device-public": "El dispositivo es público", "select-device": "Seleccionar dispositivo", + "import": "Importar dispositivo", "device-file": "Archivo de dispositivo", - "import": "Importar dispositivo" + "search": "Buscar dispositivos", + "selected-devices": "{ count, plural, 1 {1 dispositivo} other {# dispositivos} } seleccionados", + "device-configuration": "Configuración del dispositivo", + "transport-configuration": "Configuración del transporte", + "wizard": { + "device-wizard": "Asistente de dispositivo", + "device-details": "Detalles del dispositivo", + "new-device-profile": "Crear un nuevo perfil de dispositivo", + "existing-device-profile": "Seleccionar un perfil existente", + "specific-configuration": "Configuración específica", + "customer-to-assign-device": "Cliente al que asignar el dispositivo", + "add-credential": "Añadir credencial" + } + }, + "device-profile": { + "device-profile": "Perfil de dispositivo", + "device-profiles": "Perfiles de dispositivo", + "all-device-profiles": "Todos", + "add": "Añadir perfil de dispositivo", + "edit": "Editar perfil de dispositivo", + "device-profile-details": "Detalles de perfil de dispositivo", + "no-device-profiles-text": "No se encontraron perfiles", + "search": "Buscar perfiles", + "selected-device-profiles": "{ count, plural, 1 {1 perfil} other {# perfiles} } seleccionados", + "no-device-profiles-matching": "No existe perfil que conincida con '{{entity}}'.", + "device-profile-required": "Se requiere perfil de dispositivo", + "idCopiedMessage": "Se ha copiado el ID de perfil al portapapeles", + "set-default": "Hacer perfil por defecto", + "delete": "Borrar perfil de dispositivo", + "copyId": "Copiar ID de perfil", + "new-device-profile-name": "Nombre de perfil", + "new-device-profile-name-required": "Se requiere nombre de perfil.", + "name": "Nombre", + "name-required": "Se requiere nombre.", + "type": "Tipo de perfil", + "type-required": "Se requiere tipo de perfil.", + "type-default": "Por defecto", + "transport-type": "Tipo de transporte", + "transport-type-required": "Se requiere tipo de transporte.", + "transport-type-default": "Por defecto", + "transport-type-default-hint": "Soporta transportes por MQTT básico, HTTP y CoAP", + "transport-type-mqtt": "MQTT", + "transport-type-mqtt-hint": "Activa ajustes avanzados de transporte MQTT", + "transport-type-lwm2m": "LWM2M", + "transport-type-lwm2m-hint": "Transporte LWM2M", + "description": "Descripción", + "default": "Defecto", + "profile-configuration": "Configuración de perfil", + "transport-configuration": "Configuración de transporte", + "default-rule-chain": "Cadena de reglas por defecto", + "select-queue-hint": "Selecciona desde el desplegable o añade un nombre personalizado.", + "delete-device-profile-title": "Eliminar el perfil '{{deviceProfileName}}'?", + "delete-device-profile-text": "Atención, tras la confirmación el perfil y todos sus datos serán borrados e irrecuperables.", + "delete-device-profiles-title": "EEliminar { count, plural, 1 {1 perfil} other {# perfiles} }?", + "delete-device-profiles-text": "Atención, tras la confirmación los perfiles seleccionados y todos sus datos serán borrados e irrecuperables.", + "set-default-device-profile-title": "Establecer el perfil '{{deviceProfileName}}' como perfil por defecto?", + "set-default-device-profile-text": "Tras la confirmación, el perfil será marcado como por defecto y será usado por todos los nuevos dispositivos que no tengan perfil especificado.", + "no-device-profiles-found": "No se encontraron perfiles.", + "create-new-device-profile": "Crear un nuevo perfil!", + "mqtt-device-topic-filters": "Filtros de topic MQTT", + "mqtt-device-topic-filters-unique": "Los filtros de topic de dispositivo MQTT deben ser únicos.", + "mqtt-device-payload-type": "Payload de dispositivo MQTT", + "mqtt-device-payload-type-json": "JSON", + "mqtt-device-payload-type-proto": "Protobuf", + "mqtt-payload-type-required": "Se requiere tipo de Payload.", + "support-level-wildcards": "Se soportan los wilcards únicos [+] y multi-nivel [#].", + "telemetry-topic-filter": "Filtro de topic en telemetría", + "telemetry-topic-filter-required": "Se requiere filtro de topic (telemetría).", + "attributes-topic-filter": "Filtro de topic en atributos", + "attributes-topic-filter-required": "Se requiere filtro de topic (atributos).", + "telemetry-proto-schema": "Proto schema de telemetría", + "telemetry-proto-schema-required": "Se requiere proto schema de telemetría.", + "attributes-proto-schema": "Proto schema de atributos", + "attributes-proto-schema-required": "Se requiere proto schema de atributos.", + "rpc-response-topic-filter": "Filtro de topic de respuesta RPC", + "rpc-response-topic-filter-required": "Se requiere fitro de respuesta RPC.", + "not-valid-pattern-topic-filter": "No es un patrón de filtro válido", + "not-valid-single-character": "Uso inválido de wildcard único", + "not-valid-multi-character": "Uso inválido de wildcard multi-nivel", + "single-level-wildcards-hint": "[+] es adecuado para cualquier nivel. Ej.: v1/devices/+/telemetry o +/devices/+/attributes.", + "multi-level-wildcards-hint": "[#] puede reemplazar el mismo filtro y debe ser el último símbolo del topic. Ej.: # o v1/devices/me/#.", + "alarm-rules": "Reglas de alarma", + "alarm-rules-with-count": "Reglas de alarma ({{count}})", + "no-alarm-rules": "No hay reglas de alarma configuradas", + "add-alarm-rule": "Añadir regla de alarma", + "edit-alarm-rule": "Editar regla de alarma", + "alarm-type": "Tipo de alarma", + "alarm-type-required": "Se requiere tipo de alarma.", + "alarm-type-unique": "El tipo de alarma, debe ser único dentro de las reglas de alarma del perfil de dispositivo.", + "create-alarm-pattern": "Crear alarma {{alarmType}}", + "create-alarm-rules": "Crear reglas de alarma", + "no-create-alarm-rules": "No hay condiciones de creación de alarma configuradas", + "add-create-alarm-rule-prompt": "Por favor, añade una regla de alarma", + "clear-alarm-rule": "Borrar regla de alarma", + "no-clear-alarm-rule": "No hay condiciones de borrado de alarma configuradas", + "add-create-alarm-rule": "Añadir crear condición (activar alarma)", + "add-clear-alarm-rule": "Añair borrar condición (limpiar alarma)", + "select-alarm-severity": "Selecciona severidad de alarma", + "alarm-severity-required": "Se requiere especificar severidad de alarma.", + "condition-duration": "Duración de condición", + "condition-duration-value": "Valor de duración", + "condition-duration-time-unit": "Unidad de tiempo", + "condition-duration-value-range": "El valor debe estar en un rango desde 1 a 2147483647.", + "condition-duration-value-pattern": "El valor de duración debe ser un número entero.", + "condition-duration-value-required": "Se requiere valor de duración.", + "condition-duration-time-unit-required": "Se requiere una unidad de tiempo.", + "advanced-settings": "Ajustes avanzados", + "alarm-rule-details": "Detalles", + "add-alarm-rule-details": "Añadir detalles", + "propagate-alarm": "Propagar alarma", + "alarm-rule-relation-types-list": "Tipos de relación para propagar", + "alarm-rule-relation-types-list-hint": "Si no está seleccionado 'propagar relaciones', las alarmas serán propagadas sin filtrar por relación.", + "alarm-details": "Detalles de alarma", + "alarm-rule-condition": "Condiciones de regla de alarma", + "enter-alarm-rule-condition-prompt": "Por favor, añade una condición de alarma", + "edit-alarm-rule-condition": "Editar condición de alarma", + "device-provisioning": "Aprovisionamiento de dispositivos", + "provision-strategy": "Estrategia de aprovisionamiento", + "provision-strategy-required": "Se requiere estrategia de aprovisionamiento.", + "provision-strategy-disabled": "Desactivado", + "provision-strategy-created-new": "Permitir crear nuevos dispositivos", + "provision-strategy-check-pre-provisioned": "Revisar dispositivos pre-aprovisionados", + "provision-device-key": "Clave de aprovisionamiento", + "provision-device-key-required": "Se requiere clave de aprovisionamiento.", + "copy-provision-key": "Copiar clave de aprovisionamiento", + "provision-key-copied-message": "La clave de aprovisionamiento se ha copiado al portapapeles", + "provision-device-secret": "Secreto de aprovisionamiento", + "provision-device-secret-required": "Se requiere secreto de aprovisionamiento.", + "copy-provision-secret": "Copiar secreto de aprovisionamiento", + "provision-secret-copied-message": "Se ha copiado el secreto de aprovisionamiento al portapapeles", + "condition": "Condición", + "condition-type": "Tipo de condición", + "condition-type-simple": "Simple", + "condition-type-duration": "Duración", + "condition-during": "Durante {{during}}", + "condition-type-repeating": "Repetitiva", + "condition-type-required": "Se requiere tipo de condición.", + "condition-repeating-value": "Nº de eventos", + "condition-repeating-value-range": "El Nº de eventos debe estar en un rango de 1 to 2147483647.", + "condition-repeating-value-pattern": "Nº de eventos debe ser un número entero.", + "condition-repeating-value-required": "Se requiere Nº de eventos.", + "condition-repeat-times": "Repetición { count, plural, 1 {1 vez} other {# veces} }", + "schedule-type": "Tipo de horario", + "schedule-type-required": "Tipo de horario requerido.", + "schedule": "Horario", + "edit-schedule": "Editar horario de alarma", + "schedule-any-time": "Siempre activo", + "schedule-specific-time": "Activo en una hora específica", + "schedule-custom": "Personalizado", + "schedule-day": { + "monday": "Lunes", + "tuesday": "Martes", + "wednesday": "Miércoles", + "thursday": "Jueves", + "friday": "Viernes", + "saturday": "Sábado", + "sunday": "Domingo" + }, + "schedule-days": "Días", + "schedule-time": "Hora", + "schedule-time-from": "De", + "schedule-time-to": "Hasta", + "schedule-days-of-week-required": "Debe ser seleccionado por lo menos un día de la semana." }, - "dialog": { + "dialog": { "close": "Cerrar diálogo" }, "direction": { @@ -766,6 +1132,10 @@ "type-devices": "Dispositivos", "list-of-devices": "{ count, plural, 1 {Un dispositivo} other {Lista de # Dispositivos} }", "device-name-starts-with": "Dispositivos cuyos nombres comiencen por '{{prefix}}'", + "type-device-profile": "Perfil de dispositivo", + "type-device-profiles": "Perfiles de dispositivo", + "list-of-device-profiles": "{ count, plural, 1 {un perfil} other {Lista de # perfiles} }", + "device-profile-name-starts-with": "Perfiles cuyo nombre empiece por '{{prefix}}'", "type-asset": "Activo", "type-assets": "Activos", "list-of-assets": "{ count, plural, 1 {Un activo} other {Lista de # activos} }", @@ -785,7 +1155,11 @@ "type-tenant": "Propietario", "type-tenants": "Propietarios", "list-of-tenants": "{ count, plural, 1 {Un propietario} other {Lista de # propietarios} }", - "tenant-name-starts-with": "Tenants cuyos nombres comiencen por '{{prefix}}'", + "tenant-name-starts-with": "Propietarios cuyo nombre comience por '{{prefix}}'", + "type-tenant-profile": "Perfil de Propietario", + "type-tenant-profiles": "Perfiles de propietario", + "list-of-tenant-profiles": "{ count, plural, 1 {Un perfil de propietario} other {Lista de # perfiles de propietario} }", + "tenant-profile-name-starts-with": "Pefiles de propietario cuyo nombre empiece por '{{prefix}}'", "type-customer": "Cliente", "type-customers": "Clientes", "list-of-customers": "{ count, plural, 1 {Un cliente} other {Lista de # clientes} }", @@ -812,6 +1186,8 @@ "rulenode-name-starts-with": "Nodos de reglas cuyos nombres comienzan con '{{prefix}}'", "type-current-customer": "Cliente Actual", "type-current-tenant": "Propietario Actual", + "type-current-user": "Usuario Actual", + "type-current-user-owner": "Usuario Propietario Actual", "search": "Buscar entidades", "selected-entities": "{ count, plural, 1 {1 entidad} other {# entidades} } seleccionadas", "entity-label": "Etiqueta de entidad", @@ -819,10 +1195,11 @@ "details": "Detalles de entidad", "no-entities-prompt": "No se han encontrado entidades", "no-data": "No hay datos que mostrar", - "columns-to-display": "Columnas a Mostrar" + "columns-to-display": "Columnas a Mostrar", + "type-api-usage-state": "Estado de uso de la API" }, "entity-field": { - "created-time": "Tiempo de creación", + "created-time": "Hora de creación", "name": "Nombre", "type": "Tipo", "first-name": "Nombre", @@ -855,6 +1232,7 @@ "duplicate-alias-error": "Alias duplicado'{{alias}}'.
Los alias de Entity View deben ser únicos en el panel.", "configure-alias": "Configurar alias '{{alias}}'", "no-entity-views-matching": "No se encontraron vistas que coincidan con '{{entity}}'.", + "public": "Público", "alias": "Alias", "alias-required": "Alias de vista de entidad es requerido.", "remove-alias": "Borrar alias de la vista de entidad", @@ -866,6 +1244,7 @@ "entity-view-name-filter-required": "Nombre del filtro de vista de entidad es requerido.", "entity-view-name-filter-no-entity-view-matched": "No se encontraron vistas de entidad que comiencen con '{{entityView}}'.", "add": "Añadir vista de entidad", + "entity-view-public": "Vista de entidad es pública", "assign-to-customer": "Asignar a cliente", "assign-entity-view-to-customer": "Asignar vista de entidad a cliente", "assign-entity-view-to-customer-text": "Por favor, seleccione las vistas de entidad para asignar al cliente", @@ -882,15 +1261,15 @@ "unassign-entity-views-action-title": "Anular asignación { count, plural, 1 {1 vista de entidad} other {# vistas de entidad} } al cliente", "assign-new-entity-view": "Asignar nueva vista de entidad", "delete-entity-view-title": "¿Está seguro que quiere borrar la vista de entidad '{{entityViewName}}'?", - "delete-entity-view-text": "¡Cuidado! Después de la confirmación, la vista de la entidad y todos los datos relacionados serán irrecuperables.", + "delete-entity-view-text": "¡Cuidado! Tras la confirmación, la vista de la entidad y todos los datos relacionados serán irrecuperables.", "delete-entity-views-title": "¿Está seguro que quiere borrar las vistas de entidad { count, plural, 1 {1 entityView} other {# entityViews} }?", "delete-entity-views-action-title": "Borrar { count, plural, 1 {1 vista de entidad} other {# vistas de entidad} }", - "delete-entity-views-text": "¡Cuidado! Después de la confirmación, todas las vistas de entidades seleccionadas se eliminarán y todos los datos relacionados serán irrecuperables.", + "delete-entity-views-text": "¡Cuidado! Tras la confirmación, todas las vistas de entidades seleccionadas se eliminarán y todos los datos relacionados serán irrecuperables.", "unassign-entity-view-title": "¿Está seguro que quiere anular la asignación de la vista de entidad '{{entityViewName}}'?", - "unassign-entity-view-text": "Después de la confirmación, la vista de la entidad quedará sin asignar y el cliente no podrá acceder a ella.", + "unassign-entity-view-text": "Tras la confirmación, la vista de la entidad quedará sin asignar y el cliente no podrá acceder a ella.", "unassign-entity-view": "Anular asignación de la vista de entidad", "unassign-entity-views-title": "¿Está seguro que quiere anular la asignación de { count, plural, 1 {1 vista de entidad} other {# vistas de entidad} }?", - "unassign-entity-views-text": "Después de la confirmación, todas las vistas de entidades seleccionadas quedarán sin asignar y el cliente no podrá acceder a ellas.", + "unassign-entity-views-text": "Tras la confirmación, todas las vistas de entidades seleccionadas quedarán sin asignar y el cliente no podrá acceder a ellas.", "entity-view-type": "Tipo de vista de entidad", "entity-view-type-required": "Tipo de vista de entidad es requerido.", "select-entity-view-type": "Seleccione el tipo de vista de entidad", @@ -899,12 +1278,14 @@ "no-entity-view-types-matching": "No se encontraron tipos de vista de entidad que coincidan con '{{entitySubtype}}'.", "entity-view-type-list-empty": "No hay tipos de vista de entidad seleccionados.", "entity-view-types": "Tipos de vista de entidad", + "created-time": "Fecha de creación", "name": "Nombre", "name-required": "Nombre Requerido.", "description": "Descripción", "events": "Eventos", "details": "Detalles", "copyId": "Copiar el Id de la vista de entidad", + "idCopiedMessage": "El Id de la vista de entidad se ha copiado al portapapeles", "assignedToCustomer": "Asignado a cliente", "unable-entity-view-device-alias-title": "No se puede eliminar el alias de vista de entidad", "unable-entity-view-device-alias-text": "El alias del dispositivo '{{entityViewAlias}}' no se puede borrar porque está siendo usado por el widget(s):
{{widgetsList}}", @@ -930,9 +1311,11 @@ "timeseries-data": "Datos de series temporales", "timeseries-data-hint": "Configure las claves de los datos de las series temporales de la entidad de destino que serán accesibles para la vista de la entidad. Los datos de esta serie temporal son de solo lectura.", "make-public-entity-view-title": "¿Está seguro de que desea que la vista de entidad '{{entityViewName}}' sea pública?", - "make-public-entity-view-text": "Después de la confirmación, la vista de la entidad y todos sus datos se harán públicos y accesibles para otros.", + "make-public-entity-view-text": "Tras la confirmación, la vista de la entidad y todos sus datos se harán públicos y accesibles para otros.", "make-private-entity-view-title": "¿Está seguro de que desea que la vista de entidad '{{entityViewName}}' sea privada?", - "make-private-entity-view-text": "Después de la confirmación, la vista de la entidad y todos sus datos se harán privados y no serán accesibles para otros." + "make-private-entity-view-text": "Tras la confirmación, la vista de la entidad y todos sus datos se harán privados y no serán accesibles para otros.", + "search": "Buscar vistas de entidad", + "selected-entity-views": "{ count, plural, 1 {1 vista de entidad} other {# vistas de entidad} } seleccionadas" }, "event": { "event-type": "Tipo de evento", @@ -965,7 +1348,7 @@ }, "extension": { "extensions": "Extensiones", - "selected-extensions": "{ count, plural, 1 {1 extension} other {# extensions} } seleccionadas", + "selected-extensions": "{ count, plural, 1 {1 extensión} other {# extensiones} } seleccionadas", "type": "Tipo", "key": "Clave", "value": "Valor", @@ -977,9 +1360,9 @@ "delete": "Borrar Extensión", "add": "Añadir Extensión", "edit": "Editar Extensión", - "delete-extension-title": "Estás seguro de borrar la extensión '{{extensionId}}'?", + "delete-extension-title": "Eliminar la extensión '{{extensionId}}'?", "delete-extension-text": "Atención, tras la confirmación la extensión y sus datos serán borrados e irrecuperables.", - "delete-extensions-title": "Estás seguro de borrar las extensiones { count, plural, 1 {1 extensión} other {# extensiones} }?", + "delete-extensions-title": "Eliminar las extensiones { count, plural, 1 {1 extensión} other {# extensiones} }?", "delete-extensions-text": "Atención, tras la confirmación todas las extensiones seleccionadas y sus datos serán borrados e irrecuperables.", "converters": "Convertidores", "converter-id": "Id de convertidor", @@ -1120,6 +1503,93 @@ "file": "Fichero de extensiones", "invalid-file-error": "Fichero de extensiones inválido" }, + "filter": { + "add": "Añadir filtro", + "edit": "Editar filtro", + "name": "Nombre de filtro", + "name-required": "Se requiere nombre de filtro.", + "duplicate-filter": "Ya existe un filtro con el mismo nombre.", + "filters": "Filtros", + "unable-delete-filter-title": "Error borrando filtro", + "unable-delete-filter-text": "El filtro '{{filter}}' no puede ser borrado debido a que está siendo usado actualmente por los siguientes widgets:
{{widgetsList}}", + "duplicate-filter-error": "Se ha encontrado un filtro duplicado '{{filter}}'.
Los filtros deben ser únicos en el panel.", + "missing-key-filters-error": "No se encontró la clave de filtros para el filtro '{{filter}}'.", + "filter": "Filtro", + "editable": "Editable", + "no-filters-found": "No se encontraron filtros.", + "no-filter-text": "No se ha especificado filtro", + "add-filter-prompt": "Por favos, añadir filtro", + "no-filter-matching": "'{{filter}}' no encontrado.", + "create-new-filter": "Crear un filtro nuevo!", + "filter-required": "Se requiere filtro.", + "operation": { + "operation": "Operación", + "equal": "igual", + "not-equal": "no igual", + "starts-with": "comienza con", + "ends-with": "acaba con", + "contains": "contiene", + "not-contains": "no contiene", + "greater": "mayor que", + "less": "menor que", + "greater-or-equal": "mayor o igual", + "less-or-equal": "menor o igual", + "and": "y", + "or": "o" + }, + "ignore-case": "Ignorar mayús/minus", + "value": "Valor", + "remove-filter": "Borrar filtro", + "preview": "Vista previa de filtro", + "no-filters": "No hay filtros configurados", + "add-filter": "Añadir filtro", + "add-complex-filter": "Añadir filtro complejo", + "add-complex": "Agregar filtro complejo", + "complex-filter": "Filtro complejo", + "edit-complex-filter": "Editar filtro complejo", + "edit-filter-user-params": "Editar parámetros de usuario del filtro", + "filter-user-params": "Filtro de parámetros de usuario (predicado)", + "user-parameters": "Parámetros de usuario", + "display-label": "Etiqueta a mostrar", + "autogenerated-label": "Auto generar etiqueta", + "order-priority": "Prioridad orden de campos", + "key-filter": "Filtros (clave)", + "key-filters": "Filtros (claves)", + "key-name": "Nombre de clave", + "key-name-required": "Se requiere nombre de clave.", + "key-type": { + "key-type": "Tipo de clave", + "attribute": "Atributo", + "timeseries": "Timeseries", + "entity-field": "Campo de entidad" + }, + "value-type": { + "value-type": "Tipo de valor", + "string": "Cadena", + "numeric": "Numerico", + "boolean": "Booleano", + "date-time": "Fecha/Hora" + }, + "value-type-required": "Se requiere tipo de valor.", + "key-value-type-change-title": "Cambiar el tipo de valor de la clave?", + "key-value-type-change-message": "Si confirmas el nuevo tipo, todos los filtros se borrarán.", + "no-key-filters": "No hay filtros claves configurados", + "add-key-filter": "Añadir filtro clave", + "remove-key-filter": "Borrar filtro clave", + "edit-key-filter": "Editar filtro clave", + "date": "Fecha", + "time": "Hora", + "current-tenant": "Admin actual", + "current-customer": "Cliente actual", + "current-user": "Usuario actual", + "current-device": "Dispositivo actual", + "default-value": "Valor por defecto", + "dynamic-source-type": "Tipo de origen dinámico", + "no-dynamic-value": "Sin valor dinámico", + "source-attribute": "Atributo de origen", + "switch-to-dynamic-value": "Cambiar a valor dinámico", + "switch-to-default-value": "Cambiar a valor por defecto" + }, "fullscreen": { "expand": "Expandir a Pantalla Completa", "exit": "Salir de Pantalla Completa", @@ -1139,7 +1609,7 @@ "connector-type-required": "Se requiere tipo conector.", "connectors": "Configuración de conectores", "create-new-gateway": "Crear un gateway nuevo", - "create-new-gateway-text": "Estás seguro de crear un nuevo gateway con el nombre: '{{gatewayName}}'?", + "create-new-gateway-text": "Crear un nuevo gateway con el nombre: '{{gatewayName}}'?", "delete": "Borrar configuración", "download-tip": "Descargar fichero de configuración", "gateway": "Gateway", @@ -1201,17 +1671,12 @@ "tls-path-private-key": "Ruta a la clave privada en el gateway", "toggle-fullscreen": "Pantalla completa fullscreen", "transformer-json-config": "Configuración JSON*", - "update-config": "Añadir/actualizar configuración JSON", - "state-title": "Estado gateway", - "show-config-tip": "Mostrar configuración gateway", - "title-show-config": "Mostrar configuración gateway", - "read-only": "Solo lectura", - "read-write": "" + "update-config": "Añadir/actualizar configuración JSON" }, "grid": { - "delete-item-title": "¿Estás seguro que quieres eliminar este item?", + "delete-item-title": "¿Quieres eliminar este item?", "delete-item-text": "Atención, tras la confirmación el item será eliminado y la información relacionada será irrecuperable.", - "delete-items-title": "¿Estás seguro que quieres eliminar { count, plural, 1 {1 item} other {# items} }?", + "delete-items-title": "¿Quieres eliminar { count, plural, 1 {1 item} other {# items} }?", "delete-items-action-title": "Eliminar { count, plural, 1 {1 item} other {# items} }", "delete-items-text": "Atención, tras la confirmación los items seleccionados serán eliminados y la información relacionada será irrecuperable.", "add-item-text": "Agregar nuevo item", @@ -1235,10 +1700,10 @@ "import": { "no-file": "Ningún archivo seleccionado", "drop-file": "Suelte un archivo JSON o haga clic para seleccionar un archivo para cargar.", + "drop-file-csv": "Suelte un archivo CSV o haga clic para seleccionar un archivo para cargar.", "column-value": "Valor", "column-title": "Título", "column-example": "Datos de ejemplo", - "drop-file-csv": "Suelte un archivo CSV o haga clic para seleccionar un archivo para cargar.", "column-key": "Clave de atributo/telemetría", "csv-delimiter": "Delimitador CSV", "csv-first-line-header": "La primera línea contiene nombres de columna.", @@ -1257,6 +1722,7 @@ "entity-field": "Campo de entidad", "access-token": "Token de acceso", "isgateway": "Es Gateway", + "activity-time-from-gateway-device": "Fecha de actividad desde el dispositivo gateway", "description": "Descripción" }, "stepper-text": { @@ -1300,6 +1766,7 @@ "legend": { "direction": "Dirección de la leyenda", "position": "Posición de la leyenda", + "sort-legend": "Ordenar claves en leyenda", "show-max": "Mostrar valor máximo", "show-min": "Mostrar valor mínimo", "show-avg": "Mostrar valor promedio", @@ -1376,20 +1843,21 @@ "any-relation-type": "Cualquier tipo", "add": "Añadir relación", "edit": "Editar relación", - "delete-to-relation-title": "¿Estás seguro que quieres eliminar la relación con la entidad '{{entityName}}'?", + "delete-to-relation-title": "¿Quieres eliminar la relación con la entidad '{{entityName}}'?", "delete-to-relation-text": "Atención, tras la confirmación la entidad '{{entityName}}' no estará relacionada con la entidad actual.", - "delete-to-relations-title": "¿Estás seguro que quieres eliminar { count, plural, 1 {1 relación} other {# relaciones} }?", + "delete-to-relations-title": "¿Quieres eliminar { count, plural, 1 {1 relación} other {# relaciones} }?", "delete-to-relations-text": "Atención, tras la confirmación todas las relaciones seleccionadas se eliminarán y sus entidades correspondientes no estarán relacionadas con la entidad actual.", - "delete-from-relation-title": "¿Estás seguro que quieres eliminar la relación con la entidad '{{entityName}}'?", + "delete-from-relation-title": "¿Quieres eliminar la relación con la entidad '{{entityName}}'?", "delete-from-relation-text": "Atención, tras la confirmación la entidad actual no estará relacionada con la entidad '{{entityName}}'.", - "delete-from-relations-title": "¿Estás seguro que quieres eliminar { count, plural, 1 {1 relación} other {# relaciones} }?", + "delete-from-relations-title": "¿Quieres eliminar { count, plural, 1 {1 relación} other {# relaciones} }?", "delete-from-relations-text": "Atención, tras la confirmación todas las relaciones seleccionadas se eliminarán y sus entidades correspondientes no estarán relacionadas con sus entidades correspondientes.", "remove-relation-filter": "Quitar filtro de relación", "add-relation-filter": "Añadir filtro de relación", "any-relation": "Cualquier relación", "relation-filters": "Filtro de relación", "additional-info": "Información adicional (JSON)", - "invalid-additional-info": "Error al analizar el fichero JSON de información adicional." + "invalid-additional-info": "Error al analizar el fichero JSON de información adicional.", + "no-relations-text": "No se encontraron relaciones" }, "rulechain": { "rulechain": "Cadena de Regla", @@ -1401,9 +1869,9 @@ "description": "Descripción", "add": "Añadir Cadena", "set-root": "Hacer la cadena de reglas Raíz", - "set-root-rulechain-title": "¿Estás seguro de que desea hacer la cadena de reglas '{{ruleChainName}}' de tipo raíz?", + "set-root-rulechain-title": "¿Desea hacer la cadena de reglas '{{ruleChainName}}' de tipo raíz?", "set-root-rulechain-text": "Tras la confirmación, la cadena de reglas se volverá raíz y manejará todos los mensajes de transporte entrantes.", - "delete-rulechain-title": "¿Estás seguro que quieres eliminar la cadena de reglas '{{ruleChainName}}'?", + "delete-rulechain-title": "¿Quieres eliminar la cadena de reglas '{{ruleChainName}}'?", "delete-rulechain-text": "Atención, tras la confirmación la cadena de reglas y todos los datos serán irrecuperables.", "delete-rulechains-title": "¿Está seguro que quieres eliminar { count, plural, 1 {1 cadena de reglas} other {# cadenas de reglas} }?", "delete-rulechains-action-title": "Eliminar { count, plural, 1 {1 cadena de reglas} other {# cadenas de reglas} }", @@ -1426,7 +1894,10 @@ "no-rulechains-matching": "No se encontraron cadenas de reglas que coincidan con '{{entity}}' .", "rulechain-required": "Cadena de reglas requerida", "management": "Gestión de reglas", - "debug-mode": "Modo Debug" + "debug-mode": "Modo Debug", + "search": "Buscar cadenas de reglas", + "selected-rulechains": "{ count, plural, 1 {1 cadena de reglas} other {# cadenas de reglas} } seleccionadas", + "open-rulechain": "Abrir cadena de reglas" }, "rulenode": { "details": "Detalles", @@ -1478,9 +1949,9 @@ "type-unknown": "Desconocido", "type-unknown-details": "Regla de nodo no resuelta", "directive-is-not-loaded": "La directiva de configuración definida '{{directiveName}}' no está disponible.", - "ui-resources-load-error": "Error al cargar los recursos de configuración ui.", + "ui-resources-load-error": "Error al cargar los recursos de configuración UI.", "invalid-target-rulechain": "No se puede resolver la cadena de reglas objetivo!", - "test-script-function": "Probar Script Función", + "test-script-function": "Probar Script de función", "message": "Mensaje", "message-type": "Tipo de mensaje", "select-message-type": "Seleccionar tipo de mensaje", @@ -1492,11 +1963,16 @@ "help": "Ayuda", "reset-debug-mode": "Restablecer el modo de depuración en todos los nodos" }, + "timezone": { + "timezone": "Zona Horaria", + "select-timezone": "Seleccionar zona horaria", + "no-timezones-matching": "No hay zonas horarias que coincidan con '{{timezone}}'.", + "timezone-required": "Se requiere zona horaria." + }, "queue": { - "select_name": "Selecciona el nombre de la cola", - "name": "Nombre Cola", - "name_required": "Necesario especificar el nombre de cola" - + "select_name": "Selecciona el nombre de la cola", + "name": "Nombre Cola", + "name_required": "Necesario especificar el nombre de cola" }, "tenant": { "tenant": "Propietario", @@ -1509,9 +1985,9 @@ "add-tenant-text": "Agregar nuevo propietario", "no-tenants-text": "Ningún propietario encontrado", "tenant-details": "Detalles del propietario", - "delete-tenant-title": "¿Estás seguro que quieres eliminar el propietario '{{tenantTitle}}'?", + "delete-tenant-title": "¿Quieres eliminar el propietario '{{tenantTitle}}'?", "delete-tenant-text": "Atención, tras la confirmación el propietario será eliminado y la información relacionada será irrecuperable.", - "delete-tenants-title": "¿Estás seguro que quieres eliminar { count, plural, 1 {1 propietario} other {# propietarios} }?", + "delete-tenants-title": "¿Quieres eliminar { count, plural, 1 {1 propietario} other {# propietarios} }?", "delete-tenants-action-title": "Eliminar { count, plural, 1 {1 propietario} other {# propietarios} }", "delete-tenants-text": "Atención, tras la confirmación los propietarios seleccionados serán eliminados y la información relacionada será irrecuperable.", "title": "Título", @@ -1524,21 +2000,110 @@ "select-tenant": "Seleccionar propietario", "no-tenants-matching": "No hay propietarios que coincidan con '{{entity}}' .", "tenant-required": "Propietario requerido", + "search": "Buscar propietarios", + "selected-tenants": "{ count, plural, 1 {1 propietario} other {# propietarios} } seleccionados", "isolated-tb-core": "Procesando en contenedor aislado", "isolated-tb-rule-engine": "Procesando en contenedor Motor de Reglas aislado", "isolated-tb-core-details": "Requiere microservicios separados por propietario aislado", "isolated-tb-rule-engine-details": "Requiere microservicios separados por propietario aislado" }, + "tenant-profile": { + "tenant-profile": "Perfil de propietario", + "tenant-profiles": "Perfiles de propietarios", + "add": "Añadir perfil de propietario", + "edit": "Editar perfil de propietario", + "tenant-profile-details": "Detalles perfil de propietario", + "no-tenant-profiles-text": "No se encontraron perfiles de propietario", + "search": "Buscar perfiles de propietario", + "selected-tenant-profiles": "{ count, plural, 1 {1 perfil de propietario} other {# perfiles de propietario} } seleccionados", + "no-tenant-profiles-matching": "No se han encontrado perfiles de propietario que coincidan con '{{entity}}'.", + "tenant-profile-required": "Se requiere perfil de propietario", + "idCopiedMessage": "El ID de perfil de propietario se ha copiado al portapapeles", + "set-default": "Hacer perfil propietario por defecto", + "delete": "Borrar perfil", + "copyId": "Copiar ID de perfil", + "name": "Nombre", + "name-required": "Se requiere nombre.", + "data": "Datos de perfil", + "profile-configuration": "Configuración de perfil", + "description": "Descripción", + "default": "Defecto", + "delete-tenant-profile-title": "Eliminar el perfil propietario '{{tenantProfileName}}'?", + "delete-tenant-profile-text": "Atención, tras la confirmación, el perfil de propietario será borrado y su información relacionada será irrecuperable.", + "delete-tenant-profiles-title": "Eliminar { count, plural, 1 {1 perfil propietario} other {# perfiles propietarios} }?", + "delete-tenant-profiles-text": "Atención, tras la confirmación, los perfiles seleccionados se eliminarán y su información relacionada será irrecuperable.", + "set-default-tenant-profile-title": "Quieres hacer el perfil propietario '{{tenantProfileName}}' por defecto?", + "set-default-tenant-profile-text": "Tras la confirmación, el perfil propietario será marcado por defecto y será usado por los nuevos perfiles propietarios que no tengan perfil específico.", + "no-tenant-profiles-found": "No se encontraron perfiles de propietario.", + "create-new-tenant-profile": "Crear un nuevo perfil!", + "maximum-devices": "Nº Máximo de dispositivos (0 - sin límite)", + "maximum-devices-required": "Nº Máximo de dispositivos requerido.", + "maximum-devices-range": "Nº Máximo de dispositivos no puede ser negativo", + "maximum-assets": "Nº Máximo de activos (0 - sin límite)", + "maximum-assets-required": "Nº Máximo de activos requerido.", + "maximum-assets-range": "Nº Máximo de activos no puede ser negativo", + "maximum-customers": "Nº Máximo de clientes (0 - sin límite)", + "maximum-customers-required": "Nº Máximo de clientes requerido.", + "maximum-customers-range": "Nº Máximo de clientes no puede ser negativo", + "maximum-users": "Nº Máximo de usuarios (0 - sin límite)", + "maximum-users-required": "Nº Máximo de usuarios requerido.", + "maximum-users-range": "Nº Máximo de usuarios no puede ser negativo", + "maximum-dashboards": "Nº Máximo de paneles (0 - sin límite)", + "maximum-dashboards-required": "Nº Máximo de paneles requerido.", + "maximum-dashboards-range": "Nº Máximo de paneles no puede ser negativo", + "maximum-rule-chains": "Nº Máximo de cadenas de reglas (0 - sin límite)", + "maximum-rule-chains-required": "Nº Máximo de cadenas de reglas requerido.", + "maximum-rule-chains-range": "Nº Máximo de cadenas de reglas no puede ser negativo", + "transport-tenant-msg-rate-limit": "Tasa de mensajes de transporte por propietario.", + "transport-tenant-telemetry-msg-rate-limit": "Tasa de mensajes de telemetría por propietario.", + "transport-tenant-telemetry-data-points-rate-limit": "Tasa de datapoints por propietario.", + "transport-device-msg-rate-limit": "Tasa de mensajes de dispositivo.", + "transport-device-telemetry-msg-rate-limit": "Tasa de mensajes de telemetría de dispositivo.", + "transport-device-telemetry-data-points-rate-limit": "Tasa de datapoints de telemetría de dispositivo.", + "max-transport-messages": "Nº Máximo de mensajes de transporte (0 - sin límite)", + "max-transport-messages-required": "Nº Máximo de mensajes de transporte requerido.", + "max-transport-messages-range": "Nº Máximo de mensajes de transporte no puede ser negativo", + "max-transport-data-points": "Nº Máximo de datapoints transporte (0 - sin límite)", + "max-transport-data-points-required": "Nº Máximo de datapoints transporte requerido.", + "max-transport-data-points-range": "Nº Máximo de datapoints transporte no puede ser negativo", + "max-r-e-executions": "Nº Máximo de ejecuciones de motor de reglas (0 - sin límite)", + "max-r-e-executions-required": "Nº Máximo de ejecuciones de motor de reglas requerido.", + "max-r-e-executions-range": "Nº Máximo de ejecuciones de motor de reglas no puede ser negativo", + "max-j-s-executions": "Nº Máximo de ejecuciones JavaScript (0 - sin límite)", + "max-j-s-executions-required": "Nº Máximo de ejecuciones JavaScript requerido.", + "max-j-s-executions-range": "Nº Máximo de ejecuciones JavaScript no puede ser negativo", + "max-d-p-storage-days": "Nº Máximo de días a grabar en datapoints (0 - sin límite)", + "max-d-p-storage-days-required": "Nº Máximo de días requerido.", + "max-d-p-storage-days-range": "Nº Máximo de días no puede ser negativo", + "default-storage-ttl-days": "Días por defecto grabado TTL (0 - sin límite)", + "default-storage-ttl-days-required": "Días por defecto TTL requerido.", + "default-storage-ttl-days-range": "Días por defecto TTL no puede ser negativo", + "max-rule-node-executions-per-message": "Nº Máximo de ejecuciones (cadena de reglas) por mensaje (0 - sin límite)", + "max-rule-node-executions-per-message-required": "Nº Máximo de ejecuciones por mensaje requerido.", + "max-rule-node-executions-per-message-range": "Nº Máximo de ejecuciones por mensaje no puede ser negativo", + "max-emails": "Nº Máximo de emails (0 - sin límite)", + "max-emails-required": "Nº Máximo de emails requerido.", + "max-emails-range": "Nº Máximo de emails no puede ser negativo", + "max-sms": "Nº Máximo de mensajes SMS (0 - sin límite)", + "max-sms-required": "Nº Máximo de mensajes SMS requerido.", + "max-sms-range": "Nº Máximo de mensajes SMS no puede ser negativo" + }, "timeinterval": { - "seconds-interval": "{ seconds, plural, 1 {1 segundo} other {# segundos} }", - "minutes-interval": "{ minutes, plural, 1 {1 minuto} other {# minutos} }", - "hours-interval": "{ hours, plural, 1 {1 hora} other {# horas} }", - "days-interval": "{ days, plural, 1 {1 día} other {# días} }", - "days": "Días", - "hours": "Horas", - "minutes": "Minutos", + "seconds-interval": "{ seconds, plural, 1 {1 segundo} other {# segundos} }", + "minutes-interval": "{ minutes, plural, 1 {1 minuto} other {# minutos} }", + "hours-interval": "{ hours, plural, 1 {1 hora} other {# horas} }", + "days-interval": "{ days, plural, 1 {1 día} other {# días} }", + "days": "Días", + "hours": "Horas", + "minutes": "Minutos", + "seconds": "Segundos", + "advanced": "Avanzado" + }, + "timeunit": { "seconds": "Segundos", - "advanced": "Avanzado" + "minutes": "Minutos", + "hours": "Horas", + "days": "Días" }, "timewindow": { "days": "{ days, plural, 1 { día } other {# días } }", @@ -1569,9 +2134,9 @@ "add-user-text": "Agregar nuevo usuario", "no-users-text": "Ningún usuario encontrado", "user-details": "Detalles del usuario", - "delete-user-title": "¿Estás seguro que quieres eliminar el usuario '{{userEmail}}'?", + "delete-user-title": "¿Eliminar el usuario '{{userEmail}}'?", "delete-user-text": "Atención, tras la confirmación el usuario seleccionado será eliminado y la información relacionada será irrecuperable.", - "delete-users-title": "¿Estás seguro que quieres eliminar { count, plural, 1 {1 usuario} other {# usuarios} }?", + "delete-users-title": "¿Eliminar { count, plural, 1 {1 usuario} other {# usuarios} }?", "delete-users-action-title": "Borrar { count, plural, 1 {1 usuario} other {# usuarios} }", "delete-users-text": "Atención, tras la confirmación los usuarios seleccionados serán eliminados y la información relacionada será irrecuperable.", "activation-email-sent-message": "Mail de activación enviado con éxito!", @@ -1597,6 +2162,8 @@ "details": "Detalles", "login-as-tenant-admin": "Iniciar sesión como Administrador Propietario", "login-as-customer-user": "Iniciar sesión como Usuario Cliente", + "search": "Buscar usuarios", + "selected-users": "{ count, plural, 1 {1 usuario} other {# usuarios} } seleccionados", "disable-account": "Deshabilitar cuenta de usuario", "enable-account": "Habilitar cuenta de usuario", "enable-account-message": "¡La cuenta de usuario se ha habilitado correctamente!", @@ -1606,18 +2173,23 @@ "type": "Tipo de valor", "string": "Cadena de texto", "string-value": "Valor de cadena de texto", + "string-value-required": "Se requiere valor de cadena de texto", "integer": "Nro entero", "integer-value": "Valor de nro entero", - "invalid-integer-value": "Valor inválido", + "integer-value-required": "Se requiere valor entero", + "invalid-integer-value": "Valor de entero inválido", "double": "Nro decimal", "double-value": "Valor nro decimal", + "double-value-required": "Se requiere valor nro decimal", "boolean": "Booleano", "boolean-value": "Valor booleano", "false": "Falso", "true": "Verdadero", "long": "Nro Largo", "json": "JSON", - "json-value": "Valor JSON" + "json-value": "Valor JSON", + "json-value-invalid": "El valor JSON tiene un formato inválido", + "json-value-required": "Se requiere valor JSON" }, "widget": { "widget-library": "Bibloteca de Widgets", @@ -1629,7 +2201,7 @@ "widget-type-load-error": "El widget no pudo ser cargado debido a estos errores:", "remove": "Eliminar widget", "edit": "Editar widget", - "remove-widget-title": "¿Estás seguro que quieres eliminar el widget '{{widgetTitle}}'?", + "remove-widget-title": "¿Eliminar el widget '{{widgetTitle}}'?", "remove-widget-text": "Atención, tras la confirmación el widget será eliminado y toda la información relacionada será irrecuperable..", "timeseries": "Series de tiempo", "search-data": "Buscar datos", @@ -1653,6 +2225,7 @@ "type": "Tipo", "resources": "Recursos", "resource-url": "URL JavaScript/CSS", + "resource-is-module": "Es módulo", "remove-resource": "Eliminar recurso", "add-resource": "Agregar recurso", "html": "HTML", @@ -1662,7 +2235,7 @@ "datakey-settings-schema": "Esquema de configuración de clave de datos", "javascript": "Javascript", "js": "JS", - "remove-widget-type-title": "¿Estás seguro que quieres eliminar el tipo del widget '{{widgetName}}'?", + "remove-widget-type-title": "¿Eliminar el tipo del widget '{{widgetName}}'?", "remove-widget-type-text": "Atención, tras la confirmación el tipo será eliminado y la información relacionada será irrecuperable.", "remove-widget-type": "Eliminar tipo de widget.", "add-widget-type": "Agregar nuevo tipo de widget", @@ -1670,7 +2243,10 @@ "widget-template-load-failed-error": "Error al cargar la plantilla del widget!", "add": "Agregar Widget", "undo": "Deshacer cambios", - "export": "Exportar widget" + "export": "Exportar widget", + "no-data": "No hay datos para mostrar en widget", + "data-overflow": "El widget muestra {{count}} de {{total}} entidades", + "alarm-data-overflow": "El widget muestra alarmas para {{allowedEntities}} entidades (máximo permitido) de {{totalEntities}} entidades" }, "widget-action": { "header-button": "Botón de encabezado widget", @@ -1683,7 +2259,14 @@ "target-dashboard-state-required": "Se requiere estado de panel de destino", "set-entity-from-widget": "Establecer entidad desde widget", "target-dashboard": "Panel de destino", - "open-right-layout": "Abrir diseño de panel (derecho)(vista móvil)" + "open-right-layout": "Abrir diseño de panel (derecho)(vista móvil)", + "open-in-separate-dialog": "Abrir en un diálogo separado", + "dialog-title": "Título del diálogo", + "dialog-hide-dashboard-toolbar": "Ocultar barra de herramientas en el diálogo", + "dialog-width": "Ancho de diálogo en porcentaje relativo al ancho del viewport", + "dialog-height": "Alto de diálogo en porcentaje relativo al alto del viewport", + "dialog-size-range-error": "El tamaño del diálogo debe ser entre un rango de 1 a 100", + "open-new-browser-tab": "Abrir en una nueva pestaña" }, "widgets-bundle": { "current": "Paquete actual", @@ -1697,9 +2280,9 @@ "empty": "Paquete de widgets vacío.", "details": "Detalles", "widgets-bundle-details": "Detalles del paquete de Widgets", - "delete-widgets-bundle-title": "¿Estás seguro que quieres eliminar el paquete de widgets '{{widgetsBundleTitle}}'?", + "delete-widgets-bundle-title": "¿Eliminar el paquete de widgets '{{widgetsBundleTitle}}'?", "delete-widgets-bundle-text": "Atención, tras la confirmación todos los paquetes seleccionados serán eliminados y su información relacionada será irrecuperable.", - "delete-widgets-bundles-title": "¿Estás seguro que deseas eliminar { count, plural, 1 {1 paquete de widgets} other {# paquetes de widgets} }?", + "delete-widgets-bundles-title": "¿Eliminar { count, plural, 1 {1 paquete de widgets} other {# paquetes de widgets} }?", "delete-widgets-bundles-action-title": "Eliminar { count, plural, 1 {1 paquete de widgets} other {# paquetes de widgets} }", "delete-widgets-bundles-text": "Atención, tras la confirmación todos los paquetes seleccionados serán eliminados y la información relacionada será irrecuperable.", "no-widgets-bundles-matching": "Ningún paquete '{{widgetsBundle}}' encontrado.", @@ -1710,7 +2293,10 @@ "export-failed-error": "Imposible exportar paquete de widgets: {{error}}", "create-new-widgets-bundle": "Crear nuevo paquete de widgets", "widgets-bundle-file": "Archivo de paquete de widgets", - "invalid-widgets-bundle-file-error": "Imposible importar paquete de widgets: Estructura de datos inválida." + "invalid-widgets-bundle-file-error": "Imposible importar paquete de widgets: Estructura de datos inválida.", + "search": "Buscar paquete de widgets", + "selected-widgets-bundles": "{ count, plural, 1 {1 paquete de widgets} other {# paquetes de widgets} } seleccionados", + "open-widgets-bundle": "Abrir paquete de widgets" }, "widget-config": { "data": "Datos", @@ -1749,6 +2335,7 @@ "action": "Acción", "add-action": "Añadir acción", "search-actions": "Buscar acciones", + "no-actions-text": "No se encontraron actiones", "action-source": "Origen de acción", "action-source-required": "Origen de acción requerido.", "action-name": "Nombre", @@ -1760,7 +2347,7 @@ "edit-action": "Editar acción", "delete-action": "Borrar acción", "delete-action-title": "Borrar acción de widget", - "delete-action-text": "Estás seguro de borrar la acción de widget con el nombre '{{actionName}}'?", + "delete-action-text": "Eliminar la acción de widget con el nombre '{{actionName}}'?", "display-icon": "Mostrar icono del título", "icon-color": "Color del icono", "icon-size": "Tamaño del icono" @@ -1828,7 +2415,7 @@ "Custom interval": "Intervalo personalizado", "Interval": "Intervalo", "Step size": "Número de pasos", - "Ok": "De acuerdo" + "Ok": "Ok" } }, "input-widgets": { @@ -1846,8 +2433,11 @@ "entity-coordinate-required": "Se requieren ambos campos (latitud y longitud)", "entity-timeseries-required": "Se requiere la serie de tiempo de la entidad", "get-location": "Obtener localización actual", + "invalid-date": "Fecha inválida", "latitude": "Latitud", "longitude": "Longitud", + "min-value-error": "El valor mínimo es {{value}}", + "max-value-error": "El valor máximo es {{value}}", "not-allowed-entity": "La entidad seleccionada no puede tener atributos compartidos", "no-attribute-selected": "No se seleccionó ningún atributo", "no-datakey-selected": "No se seleccionó ninguna clave de datos", @@ -1856,6 +2446,9 @@ "no-image": "Sin imagen", "no-support-geolocation": "Tu navegador no soporta geolocalización", "no-support-web-camera": "No hay cámara web compatible", + "enable-https-use-widget": "Por favor, activa HTTPS para poder usar este widget", + "no-found-your-camera": "No es posible encontrar la cámara", + "no-permission-camera": "Permiso denegado por el usuario / Esta página no tiene permisos para usar la cámara", "no-timeseries-selected": "No hay series de tiempo seleccionadas", "secret-key": "Clave", "secret-key-required": "Clave requerida", From db904c69637b4a6d716b8551943728a695f912d8 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Mon, 1 Feb 2021 13:30:03 +0200 Subject: [PATCH 103/249] Fix HSQLDB support --- .../HsqlEntityDatabaseSchemaService.java | 25 +++++++++++++++++++ .../SqlAbstractDatabaseSchemaService.java | 4 +-- .../dao/sql/query/EntityDataAdapter.java | 2 +- .../resources/sql/schema-entities-hsql.sql | 2 +- 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/install/HsqlEntityDatabaseSchemaService.java b/application/src/main/java/org/thingsboard/server/service/install/HsqlEntityDatabaseSchemaService.java index e8b90ae8fe..b333cafce2 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/HsqlEntityDatabaseSchemaService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/HsqlEntityDatabaseSchemaService.java @@ -15,11 +15,20 @@ */ package org.thingsboard.server.service.install; +import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; import org.thingsboard.server.dao.util.HsqlDao; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.sql.Connection; +import java.sql.DriverManager; + @Service +@Slf4j @HsqlDao @Profile("install") public class HsqlEntityDatabaseSchemaService extends SqlAbstractDatabaseSchemaService @@ -27,5 +36,21 @@ public class HsqlEntityDatabaseSchemaService extends SqlAbstractDatabaseSchemaSe protected HsqlEntityDatabaseSchemaService() { super("schema-entities-hsql.sql", "schema-entities-idx.sql"); } + + private final String schemaTypesSql = "schema-types-hsql.sql"; + + @Override + public void createDatabaseSchema(boolean createIndexes) throws Exception { + + log.info("Installing SQL DataBase types part: " + schemaTypesSql); + + Path schemaFile = Paths.get(installScripts.getDataDir(), SQL_DIR, schemaTypesSql); + try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { + String sql = new String(Files.readAllBytes(schemaFile), Charset.forName("UTF-8")); + conn.createStatement().execute(sql); //NOSONAR, ignoring because method used to load initial thingsboard database schema + } + + super.createDatabaseSchema(createIndexes); + } } diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlAbstractDatabaseSchemaService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlAbstractDatabaseSchemaService.java index f823c40e69..1e652880a0 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlAbstractDatabaseSchemaService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlAbstractDatabaseSchemaService.java @@ -30,7 +30,7 @@ import java.sql.SQLException; @Slf4j public abstract class SqlAbstractDatabaseSchemaService implements DatabaseSchemaService { - private static final String SQL_DIR = "sql"; + protected static final String SQL_DIR = "sql"; @Value("${spring.datasource.url}") protected String dbUrl; @@ -42,7 +42,7 @@ public abstract class SqlAbstractDatabaseSchemaService implements DatabaseSchema protected String dbPassword; @Autowired - private InstallScripts installScripts; + protected InstallScripts installScripts; private final String schemaSql; private final String schemaIdxSql; diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityDataAdapter.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityDataAdapter.java index 230c23b604..785ba69c7e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityDataAdapter.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityDataAdapter.java @@ -83,7 +83,7 @@ public class EntityDataAdapter { if (value != null) { String strVal = value.toString(); // check number - if (strVal.length() > 0 && NumberUtils.isParsable(strVal)) { + if (NumberUtils.isNumber(strVal)) { try { long longVal = Long.parseLong(strVal); return Long.toString(longVal); diff --git a/dao/src/main/resources/sql/schema-entities-hsql.sql b/dao/src/main/resources/sql/schema-entities-hsql.sql index 09dd42b622..ee658f8da4 100644 --- a/dao/src/main/resources/sql/schema-entities-hsql.sql +++ b/dao/src/main/resources/sql/schema-entities-hsql.sql @@ -114,7 +114,7 @@ CREATE TABLE IF NOT EXISTS customer ( CREATE TABLE IF NOT EXISTS dashboard ( id uuid NOT NULL CONSTRAINT dashboard_pkey PRIMARY KEY, created_time bigint NOT NULL, - configuration varchar, + configuration varchar(10000000), assigned_customers varchar(1000000), search_text varchar(255), tenant_id uuid, From 1643188ab24cf8ffec05525b2cfa262e8d3c9041 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Mon, 1 Feb 2021 13:45:26 +0200 Subject: [PATCH 104/249] Fix tests --- .../server/dao/service/BaseEntityServiceTest.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseEntityServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseEntityServiceTest.java index 70d97a8726..7c7a3fa3d7 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseEntityServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseEntityServiceTest.java @@ -827,10 +827,7 @@ public abstract class BaseEntityServiceTest extends AbstractServiceTest { .getLatest().get(EntityKeyType.TIME_SERIES).get("temperature").getValue()); } List deviceTemperatures = temperatures.stream().map(aDouble -> Double.toString(aDouble)).collect(Collectors.toList()); - if (DaoTestUtil.getSqlDbType(template) == SqlDbType.H2) { - // in H2 double values are stored with E0 in the end of the string - loadedTemperatures = loadedTemperatures.stream().map(s -> s.substring(0, s.length() - 2)).collect(Collectors.toList()); - } + Assert.assertEquals(deviceTemperatures, loadedTemperatures); pageLink = new EntityDataPageLink(10, 0, null, sortOrder); @@ -858,10 +855,6 @@ public abstract class BaseEntityServiceTest extends AbstractServiceTest { entityData.getLatest().get(EntityKeyType.TIME_SERIES).get("temperature").getValue()).collect(Collectors.toList()); List deviceHighTemperatures = highTemperatures.stream().map(aDouble -> Double.toString(aDouble)).collect(Collectors.toList()); - if (DaoTestUtil.getSqlDbType(template) == SqlDbType.H2) { - // in H2 double values are stored with E0 in the end of the string - loadedHighTemperatures = loadedHighTemperatures.stream().map(s -> s.substring(0, s.length() - 2)).collect(Collectors.toList()); - } Assert.assertEquals(deviceHighTemperatures, loadedHighTemperatures); deviceService.deleteDevicesByTenantId(tenantId); From 949d4db5260fceb5b2581a825a001b42ed5d9594 Mon Sep 17 00:00:00 2001 From: Sergey Tarnavskiy Date: Mon, 1 Feb 2021 17:19:00 +0200 Subject: [PATCH 105/249] Added First/Last page-buttons to the tables-paginator --- .../home/components/attribute/attribute-table.component.html | 3 ++- .../home/components/entity/entities-table.component.html | 3 ++- .../components/widget/lib/alarms-table-widget.component.html | 3 ++- .../components/widget/lib/entities-table-widget.component.html | 3 ++- .../widget/lib/timeseries-table-widget.component.html | 3 ++- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html index ee1fc9c96e..769c8a08af 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html +++ b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html @@ -195,7 +195,8 @@ [length]="dataSource.total() | async" [pageIndex]="pageLink.page" [pageSize]="pageLink.pageSize" - [pageSizeOptions]="[10, 20, 30]"> + [pageSizeOptions]="[10, 20, 30]" + showFirstLastButtons> + [pageSizeOptions]="pageSizeOptions" + showFirstLastButtons>

diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html index 34dc83f80c..8855e8aa9c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html @@ -140,6 +140,7 @@ [length]="alarmsDatasource.total() | async" [pageIndex]="pageLink.page" [pageSize]="pageLink.pageSize" - [pageSizeOptions]="pageSizeOptions"> + [pageSizeOptions]="pageSizeOptions" + showFirstLastButtons>
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html index eea93478d1..cc6a6a198b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html @@ -99,6 +99,7 @@ [length]="entityDatasource.total() | async" [pageIndex]="pageLink.page" [pageSize]="pageLink.pageSize" - [pageSizeOptions]="pageSizeOptions"> + [pageSizeOptions]="pageSizeOptions" + showFirstLastButtons>
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html index b6ff0b2fbb..5f8c94727d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html @@ -104,7 +104,8 @@ [length]="source.timeseriesDatasource.total() | async" [pageIndex]="source.pageLink.page" [pageSize]="source.pageLink.pageSize" - [pageSizeOptions]="pageSizeOptions"> + [pageSizeOptions]="pageSizeOptions" + showFirstLastButtons> From 8860985a49d95610509b3fd32c17dcd170b600cb Mon Sep 17 00:00:00 2001 From: Chantsova Ekaterina Date: Mon, 1 Feb 2021 18:36:18 +0200 Subject: [PATCH 106/249] Make table to show correct milliseconds value --- .../components/widget/lib/timeseries-table-widget.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts index e21e29ba65..4ce340d8ea 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts @@ -210,7 +210,7 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI this.displayPagination = isDefined(this.settings.displayPagination) ? this.settings.displayPagination : true; this.hideEmptyLines = isDefined(this.settings.hideEmptyLines) ? this.settings.hideEmptyLines : false; this.showTimestamp = this.settings.showTimestamp !== false; - this.dateFormatFilter = (this.settings.showMilliseconds !== true) ? 'yyyy-MM-dd HH:mm:ss' : 'yyyy-MM-dd HH:mm:ss.sss'; + this.dateFormatFilter = (this.settings.showMilliseconds !== true) ? 'yyyy-MM-dd HH:mm:ss' : 'yyyy-MM-dd HH:mm:ss.SSS'; const pageSize = this.settings.defaultPageSize; if (isDefined(pageSize) && isNumber(pageSize) && pageSize > 0) { From 96bea44604812e6347e2ff98fd7989c84d860217 Mon Sep 17 00:00:00 2001 From: Vladyslav Prykhodko Date: Tue, 2 Feb 2021 00:45:42 +0200 Subject: [PATCH 107/249] UI: Fixed show widget action dialog in Safari browser --- .../widget-action-dialog.component.html | 42 +++++++++---------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/action/widget-action-dialog.component.html b/ui-ngx/src/app/modules/home/components/widget/action/widget-action-dialog.component.html index d8f25c0321..33678c88b3 100644 --- a/ui-ngx/src/app/modules/home/components/widget/action/widget-action-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/action/widget-action-dialog.component.html @@ -67,15 +67,13 @@
-
-
widget-action.target-dashboard
- -
+
widget-action.target-dashboard
+
-
- - {{ 'widget-action.set-entity-from-widget' | translate }} - - - alias.state-entity-parameter-name - - -
+ + {{ 'widget-action.set-entity-from-widget' | translate }} + + + alias.state-entity-parameter-name + +
{{ 'widget-action.open-in-separate-dialog' | translate }} -
+
widget-action.dialog-title From 64d4d9016556211e1cc48e39ca16be4d8644d9ba Mon Sep 17 00:00:00 2001 From: Chantsova Ekaterina Date: Tue, 2 Feb 2021 15:20:43 +0200 Subject: [PATCH 108/249] Refactoring: replace deprecated PortalInjector --- .../alias/aliases-entity-select.component.ts | 25 +++++--- .../attribute/attribute-table.component.ts | 24 +++++--- .../filter/filters-edit.component.ts | 25 +++++--- .../widget/legend-config.component.ts | 27 ++++++--- .../lib/alarms-table-widget.component.ts | 60 ++++++++++++------- .../date-range-navigator.component.ts | 34 +++++++---- .../lib/entities-table-widget.component.ts | 32 ++++++---- .../components/dashboard-select.component.ts | 26 +++++--- .../components/time/timewindow.component.ts | 27 ++++++--- .../app/shared/components/toast.directive.ts | 11 ++-- 10 files changed, 190 insertions(+), 101 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/alias/aliases-entity-select.component.ts b/ui-ngx/src/app/modules/home/components/alias/aliases-entity-select.component.ts index ae6eeaadf9..ad7b3c6a11 100644 --- a/ui-ngx/src/app/modules/home/components/alias/aliases-entity-select.component.ts +++ b/ui-ngx/src/app/modules/home/components/alias/aliases-entity-select.component.ts @@ -14,14 +14,23 @@ /// limitations under the License. /// -import { Component, Input, OnDestroy, OnInit, ViewChild, ViewContainerRef } from '@angular/core'; +import { + Component, + Injector, + Input, + OnDestroy, + OnInit, + StaticProvider, + ViewChild, + ViewContainerRef +} from '@angular/core'; import { TooltipPosition } from '@angular/material/tooltip'; import { AliasInfo, IAliasController } from '@core/api/widget-api.models'; import { CdkOverlayOrigin, ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay'; import { TranslateService } from '@ngx-translate/core'; import { Subscription } from 'rxjs'; import { BreakpointObserver } from '@angular/cdk/layout'; -import { ComponentPortal, PortalInjector } from '@angular/cdk/portal'; +import { ComponentPortal } from '@angular/cdk/portal'; import { ALIASES_ENTITY_SELECT_PANEL_DATA, AliasesEntitySelectPanelComponent, @@ -136,12 +145,12 @@ export class AliasesEntitySelectComponent implements OnInit, OnDestroy { overlayRef.attach(new ComponentPortal(AliasesEntitySelectPanelComponent, this.viewContainerRef, injector)); } - private _createAliasesEntitySelectPanelInjector(overlayRef: OverlayRef, data: AliasesEntitySelectPanelData): PortalInjector { - const injectionTokens = new WeakMap([ - [ALIASES_ENTITY_SELECT_PANEL_DATA, data], - [OverlayRef, overlayRef] - ]); - return new PortalInjector(this.viewContainerRef.injector, injectionTokens); + private _createAliasesEntitySelectPanelInjector(overlayRef: OverlayRef, data: AliasesEntitySelectPanelData): Injector { + const providers: StaticProvider[] = [ + {provide: ALIASES_ENTITY_SELECT_PANEL_DATA, useValue: data}, + {provide: OverlayRef, useValue: overlayRef} + ]; + return Injector.create({parent: this.viewContainerRef.injector, providers}); } private updateDisplayValue() { diff --git a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts index 6ad889ef0e..6456e6d6ed 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts @@ -19,9 +19,11 @@ import { ChangeDetectionStrategy, Component, ElementRef, + Injector, Input, NgZone, OnInit, + StaticProvider, ViewChild, ViewContainerRef } from '@angular/core'; @@ -62,7 +64,7 @@ import { EditAttributeValuePanelComponent, EditAttributeValuePanelData } from './edit-attribute-value-panel.component'; -import { ComponentPortal, PortalInjector } from '@angular/cdk/portal'; +import { ComponentPortal } from '@angular/cdk/portal'; import { TelemetryWebsocketService } from '@core/ws/telemetry-websocket.service'; import { WidgetsBundle } from '@shared/models/widgets-bundle.model'; import { DataKey, Datasource, DatasourceType, Widget, widgetType } from '@shared/models/widget.models'; @@ -319,13 +321,19 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI overlayRef.backdropClick().subscribe(() => { overlayRef.dispose(); }); - const injectionTokens = new WeakMap([ - [EDIT_ATTRIBUTE_VALUE_PANEL_DATA, { - attributeValue: attribute.value - } as EditAttributeValuePanelData], - [OverlayRef, overlayRef] - ]); - const injector = new PortalInjector(this.viewContainerRef.injector, injectionTokens); + const providers: StaticProvider[] = [ + { + provide: EDIT_ATTRIBUTE_VALUE_PANEL_DATA, + useValue: { + attributeValue: attribute.value + } as EditAttributeValuePanelData + }, + { + provide: OverlayRef, + useValue: overlayRef + } + ]; + const injector = Injector.create({parent: this.viewContainerRef.injector, providers}); const componentRef = overlayRef.attach(new ComponentPortal(EditAttributeValuePanelComponent, this.viewContainerRef, injector)); componentRef.onDestroy(() => { diff --git a/ui-ngx/src/app/modules/home/components/filter/filters-edit.component.ts b/ui-ngx/src/app/modules/home/components/filter/filters-edit.component.ts index e5023e624b..73d2954572 100644 --- a/ui-ngx/src/app/modules/home/components/filter/filters-edit.component.ts +++ b/ui-ngx/src/app/modules/home/components/filter/filters-edit.component.ts @@ -14,7 +14,16 @@ /// limitations under the License. /// -import { Component, Input, OnDestroy, OnInit, ViewChild, ViewContainerRef } from '@angular/core'; +import { + Component, + Injector, + Input, + OnDestroy, + OnInit, + StaticProvider, + ViewChild, + ViewContainerRef +} from '@angular/core'; import { TooltipPosition } from '@angular/material/tooltip'; import { IAliasController } from '@core/api/widget-api.models'; import { CdkOverlayOrigin, ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay'; @@ -28,7 +37,7 @@ import { FiltersEditPanelComponent, FiltersEditPanelData } from '@home/components/filter/filters-edit-panel.component'; -import { ComponentPortal, PortalInjector } from '@angular/cdk/portal'; +import { ComponentPortal } from '@angular/cdk/portal'; import { UserFilterDialogComponent, UserFilterDialogData } from '@home/components/filter/user-filter-dialog.component'; import { MatDialog } from '@angular/material/dialog'; @@ -153,12 +162,12 @@ export class FiltersEditComponent implements OnInit, OnDestroy { } } - private _createFiltersEditPanelInjector(overlayRef: OverlayRef, data: FiltersEditPanelData): PortalInjector { - const injectionTokens = new WeakMap([ - [FILTER_EDIT_PANEL_DATA, data], - [OverlayRef, overlayRef] - ]); - return new PortalInjector(this.viewContainerRef.injector, injectionTokens); + private _createFiltersEditPanelInjector(overlayRef: OverlayRef, data: FiltersEditPanelData): Injector { + const providers: StaticProvider[] = [ + {provide: FILTER_EDIT_PANEL_DATA, useValue: data}, + {provide: OverlayRef, useValue: overlayRef} + ]; + return Injector.create({parent: this.viewContainerRef.injector, providers}); } private updateFiltersInfo() { diff --git a/ui-ngx/src/app/modules/home/components/widget/legend-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/legend-config.component.ts index e16749191e..6072bf7eaf 100644 --- a/ui-ngx/src/app/modules/home/components/widget/legend-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/legend-config.component.ts @@ -14,11 +14,22 @@ /// limitations under the License. /// -import { Component, forwardRef, Inject, Input, OnDestroy, OnInit, ViewChild, ViewContainerRef } from '@angular/core'; +import { + Component, + forwardRef, + Inject, + Injector, + Input, + OnDestroy, + OnInit, + StaticProvider, + ViewChild, + ViewContainerRef +} from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { DOCUMENT } from '@angular/common'; import { CdkOverlayOrigin, ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay'; -import { ComponentPortal, PortalInjector } from '@angular/cdk/portal'; +import { ComponentPortal } from '@angular/cdk/portal'; import { MediaBreakpoints } from '@shared/models/constants'; import { BreakpointObserver } from '@angular/cdk/layout'; import { WINDOW } from '@core/services/window.service'; @@ -140,12 +151,12 @@ export class LegendConfigComponent implements OnInit, OnDestroy, ControlValueAcc overlayRef.attach(new ComponentPortal(LegendConfigPanelComponent, this.viewContainerRef, injector)); } - private _createLegendConfigPanelInjector(overlayRef: OverlayRef, data: LegendConfigPanelData): PortalInjector { - const injectionTokens = new WeakMap([ - [LEGEND_CONFIG_PANEL_DATA, data], - [OverlayRef, overlayRef] - ]); - return new PortalInjector(this.viewContainerRef.injector, injectionTokens); + private _createLegendConfigPanelInjector(overlayRef: OverlayRef, data: LegendConfigPanelData): Injector { + const providers: StaticProvider[] = [ + {provide: LEGEND_CONFIG_PANEL_DATA, useValue: data}, + {provide: OverlayRef, useValue: overlayRef} + ]; + return Injector.create({parent: this.viewContainerRef.injector, providers}); } registerOnChange(fn: any): void { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts index d5ba2aca5b..d58ace0a6b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts @@ -19,9 +19,11 @@ import { Component, ElementRef, EventEmitter, + Injector, Input, NgZone, OnInit, + StaticProvider, ViewChild, ViewContainerRef } from '@angular/core'; @@ -64,7 +66,7 @@ import { widthStyle } from '@home/components/widget/lib/table-widget.models'; import { ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay'; -import { ComponentPortal, PortalInjector } from '@angular/cdk/portal'; +import { ComponentPortal } from '@angular/cdk/portal'; import { DISPLAY_COLUMNS_PANEL_DATA, DisplayColumnsPanelComponent, @@ -452,20 +454,26 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, }; }); - const injectionTokens = new WeakMap([ - [DISPLAY_COLUMNS_PANEL_DATA, { - columns, - columnsUpdated: (newColumns) => { - this.displayedColumns = newColumns.filter(column => column.display).map(column => column.def); - if (this.enableSelection) { - this.displayedColumns.unshift('select'); + const providers: StaticProvider[] = [ + { + provide: DISPLAY_COLUMNS_PANEL_DATA, + useValue: { + columns, + columnsUpdated: (newColumns) => { + this.displayedColumns = newColumns.filter(column => column.display).map(column => column.def); + if (this.enableSelection) { + this.displayedColumns.unshift('select'); + } + this.displayedColumns.push('actions'); } - this.displayedColumns.push('actions'); - } - } as DisplayColumnsPanelData], - [OverlayRef, overlayRef] - ]); - const injector = new PortalInjector(this.viewContainerRef.injector, injectionTokens); + } as DisplayColumnsPanelData + }, + { + provide: OverlayRef, + useValue: overlayRef + } + ]; + const injector = Injector.create({parent: this.viewContainerRef.injector, providers}); overlayRef.attach(new ComponentPortal(DisplayColumnsPanelComponent, this.viewContainerRef, injector)); this.ctx.detectChanges(); @@ -492,15 +500,21 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, overlayRef.backdropClick().subscribe(() => { overlayRef.dispose(); }); - const injectionTokens = new WeakMap([ - [ALARM_FILTER_PANEL_DATA, { - statusList: this.pageLink.statusList, - severityList: this.pageLink.severityList, - typeList: this.pageLink.typeList - } as AlarmFilterPanelData], - [OverlayRef, overlayRef] - ]); - const injector = new PortalInjector(this.viewContainerRef.injector, injectionTokens); + const providers: StaticProvider[] = [ + { + provide: ALARM_FILTER_PANEL_DATA, + useValue: { + statusList: this.pageLink.statusList, + severityList: this.pageLink.severityList, + typeList: this.pageLink.typeList + } as AlarmFilterPanelData + }, + { + provide: OverlayRef, + useValue: overlayRef + } + ]; + const injector = Injector.create({parent: this.viewContainerRef.injector, providers}); const componentRef = overlayRef.attach(new ComponentPortal(AlarmFilterPanelComponent, this.viewContainerRef, injector)); componentRef.onDestroy(() => { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/date-range-navigator/date-range-navigator.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/date-range-navigator/date-range-navigator.component.ts index 7edd0506b3..e3b51c61cb 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/date-range-navigator/date-range-navigator.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/date-range-navigator/date-range-navigator.component.ts @@ -18,9 +18,11 @@ import { Component, Inject, InjectionToken, + Injector, Input, OnDestroy, OnInit, + StaticProvider, ViewChild, ViewContainerRef, ViewEncapsulation @@ -41,7 +43,7 @@ import { import { KeyValue } from '@angular/common'; import * as _moment from 'moment'; import { ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay'; -import { ComponentPortal, PortalInjector } from '@angular/cdk/portal'; +import { ComponentPortal } from '@angular/cdk/portal'; import { MatSelect } from '@angular/material/select'; import { Subscription } from 'rxjs'; import { HistoryWindowType, TimewindowType } from '@shared/models/time/time.models'; @@ -142,18 +144,24 @@ export class DateRangeNavigatorWidgetComponent extends PageComponent implements overlayRef.backdropClick().subscribe(() => { overlayRef.dispose(); }); - const injectionTokens = new WeakMap([ - [DATE_RANGE_NAVIGATOR_PANEL_DATA, { - model: cloneDateRangeNavigatorModel(this.advancedModel), - settings: this.settings, - onChange: model => { - this.advancedModel = model; - this.triggerChange(); - } - } as DateRangeNavigatorPanelData], - [OverlayRef, overlayRef] - ]); - const injector = new PortalInjector(this.viewContainerRef.injector, injectionTokens); + const providers: StaticProvider[] = [ + { + provide: DATE_RANGE_NAVIGATOR_PANEL_DATA, + useValue: { + model: cloneDateRangeNavigatorModel(this.advancedModel), + settings: this.settings, + onChange: model => { + this.advancedModel = model; + this.triggerChange(); + } + } as DateRangeNavigatorPanelData + }, + { + provide: OverlayRef, + useValue: overlayRef + } + ]; + const injector = Injector.create({parent: this.viewContainerRef.injector, providers}); overlayRef.attach(new ComponentPortal(DateRangeNavigatorPanelComponent, this.viewContainerRef, injector)); this.ctx.detectChanges(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts index f75f07ae69..25b036a467 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts @@ -18,9 +18,11 @@ import { AfterViewInit, Component, ElementRef, + Injector, Input, NgZone, OnInit, + StaticProvider, ViewChild, ViewContainerRef } from '@angular/core'; @@ -70,7 +72,7 @@ import { widthStyle } from '@home/components/widget/lib/table-widget.models'; import { ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay'; -import { ComponentPortal, PortalInjector } from '@angular/cdk/portal'; +import { ComponentPortal } from '@angular/cdk/portal'; import { DISPLAY_COLUMNS_PANEL_DATA, DisplayColumnsPanelComponent, @@ -422,17 +424,23 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni }; }); - const injectionTokens = new WeakMap([ - [DISPLAY_COLUMNS_PANEL_DATA, { - columns, - columnsUpdated: (newColumns) => { - this.displayedColumns = newColumns.filter(column => column.display).map(column => column.def); - this.displayedColumns.push('actions'); - } - } as DisplayColumnsPanelData], - [OverlayRef, overlayRef] - ]); - const injector = new PortalInjector(this.viewContainerRef.injector, injectionTokens); + const providers: StaticProvider[] = [ + { + provide: DISPLAY_COLUMNS_PANEL_DATA, + useValue: { + columns, + columnsUpdated: (newColumns) => { + this.displayedColumns = newColumns.filter(column => column.display).map(column => column.def); + this.displayedColumns.push('actions'); + } + } as DisplayColumnsPanelData + }, + { + provide: OverlayRef, + useValue: overlayRef + } + ]; + const injector = Injector.create({parent: this.viewContainerRef.injector, providers}); overlayRef.attach(new ComponentPortal(DisplayColumnsPanelComponent, this.viewContainerRef, injector)); this.ctx.detectChanges(); diff --git a/ui-ngx/src/app/shared/components/dashboard-select.component.ts b/ui-ngx/src/app/shared/components/dashboard-select.component.ts index 7357a1aa5a..64a8eb42c1 100644 --- a/ui-ngx/src/app/shared/components/dashboard-select.component.ts +++ b/ui-ngx/src/app/shared/components/dashboard-select.component.ts @@ -14,7 +14,17 @@ /// limitations under the License. /// -import { Component, forwardRef, Inject, Input, OnInit, ViewChild, ViewContainerRef } from '@angular/core'; +import { + Component, + forwardRef, + Inject, + Injector, + Input, + OnInit, + StaticProvider, + ViewChild, + ViewContainerRef +} from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { Observable, of } from 'rxjs'; import { PageLink } from '@shared/models/page/page-link'; @@ -32,7 +42,7 @@ import { CdkOverlayOrigin, ConnectedPosition, Overlay, OverlayConfig, OverlayRef import { BreakpointObserver } from '@angular/cdk/layout'; import { DOCUMENT } from '@angular/common'; import { WINDOW } from '@core/services/window.service'; -import { ComponentPortal, PortalInjector } from '@angular/cdk/portal'; +import { ComponentPortal } from '@angular/cdk/portal'; import { DASHBOARD_SELECT_PANEL_DATA, DashboardSelectPanelComponent, @@ -186,12 +196,12 @@ export class DashboardSelectComponent implements ControlValueAccessor, OnInit { overlayRef.attach(new ComponentPortal(DashboardSelectPanelComponent, this.viewContainerRef, injector)); } - private _createDashboardSelectPanelInjector(overlayRef: OverlayRef, data: DashboardSelectPanelData): PortalInjector { - const injectionTokens = new WeakMap([ - [DASHBOARD_SELECT_PANEL_DATA, data], - [OverlayRef, overlayRef] - ]); - return new PortalInjector(this.viewContainerRef.injector, injectionTokens); + private _createDashboardSelectPanelInjector(overlayRef: OverlayRef, data: DashboardSelectPanelData): Injector { + const providers: StaticProvider[] = [ + {provide: DASHBOARD_SELECT_PANEL_DATA, useValue: data}, + {provide: OverlayRef, useValue: overlayRef} + ]; + return Injector.create({parent: this.viewContainerRef.injector, providers}); } private updateView() { diff --git a/ui-ngx/src/app/shared/components/time/timewindow.component.ts b/ui-ngx/src/app/shared/components/time/timewindow.component.ts index 6e61680b09..e1be42eff3 100644 --- a/ui-ngx/src/app/shared/components/time/timewindow.component.ts +++ b/ui-ngx/src/app/shared/components/time/timewindow.component.ts @@ -14,7 +14,18 @@ /// limitations under the License. /// -import { Component, forwardRef, Inject, Input, OnDestroy, OnInit, ViewChild, ViewContainerRef } from '@angular/core'; +import { + Component, + forwardRef, + Inject, + Injector, + Input, + OnDestroy, + OnInit, + StaticProvider, + ViewChild, + ViewContainerRef +} from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { TranslateService } from '@ngx-translate/core'; import { MillisecondsToTimeStringPipe } from '@shared/pipe/milliseconds-to-time-string.pipe'; @@ -32,7 +43,7 @@ import { TimewindowPanelComponent, TimewindowPanelData } from '@shared/components/time/timewindow-panel.component'; -import { ComponentPortal, PortalInjector } from '@angular/cdk/portal'; +import { ComponentPortal } from '@angular/cdk/portal'; import { MediaBreakpoints } from '@shared/models/constants'; import { BreakpointObserver } from '@angular/cdk/layout'; import { WINDOW } from '@core/services/window.service'; @@ -229,12 +240,12 @@ export class TimewindowComponent implements OnInit, OnDestroy, ControlValueAcces }); } - private _createTimewindowPanelInjector(overlayRef: OverlayRef, data: TimewindowPanelData): PortalInjector { - const injectionTokens = new WeakMap([ - [TIMEWINDOW_PANEL_DATA, data], - [OverlayRef, overlayRef] - ]); - return new PortalInjector(this.viewContainerRef.injector, injectionTokens); + private _createTimewindowPanelInjector(overlayRef: OverlayRef, data: TimewindowPanelData): Injector { + const providers: StaticProvider[] = [ + {provide: TIMEWINDOW_PANEL_DATA, useValue: data}, + {provide: OverlayRef, useValue: overlayRef} + ]; + return Injector.create({parent: this.viewContainerRef.injector, providers}); } registerOnChange(fn: any): void { diff --git a/ui-ngx/src/app/shared/components/toast.directive.ts b/ui-ngx/src/app/shared/components/toast.directive.ts index af4494338d..addecfb57a 100644 --- a/ui-ngx/src/app/shared/components/toast.directive.ts +++ b/ui-ngx/src/app/shared/components/toast.directive.ts @@ -20,9 +20,11 @@ import { Directive, ElementRef, HostBinding, Inject, + Injector, Input, NgZone, OnDestroy, Optional, + StaticProvider, ViewChild, ViewContainerRef } from '@angular/core'; @@ -34,7 +36,6 @@ import { BreakpointObserver } from '@angular/cdk/layout'; import { MediaBreakpoints } from '@shared/models/constants'; import { MatButton } from '@angular/material/button'; import Timeout = NodeJS.Timeout; -import { PortalInjector } from '@angular/cdk/portal'; @Directive({ selector: '[tb-toast]' @@ -138,10 +139,10 @@ export class ToastDirective implements AfterViewInit, OnDestroy { this.toastComponentRef.destroy(); } }; - const injectionTokens = new WeakMap([ - [MAT_SNACK_BAR_DATA, data] - ]); - const injector = new PortalInjector(this.viewContainerRef.injector, injectionTokens); + const providers: StaticProvider[] = [ + {provide: MAT_SNACK_BAR_DATA, useValue: data} + ]; + const injector = Injector.create({parent: this.viewContainerRef.injector, providers}); this.toastComponentRef = this.viewContainerRef.createComponent(componentFactory, 0, injector); this.cd.detectChanges(); From 3ea5314495c857796198a9183e2a160562a2f87f Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 3 Feb 2021 12:21:55 +0200 Subject: [PATCH 109/249] Home dashboard feature. Enable tooltips for flot chars in mobile mode. Disable widgets interaction in widget library and when adding widget to dashboard. --- .../json/system/widget_bundles/charts.json | 52 ++++---- .../widget_bundles/navigation_widgets.json | 41 +++++++ .../controller/DashboardController.java | 107 ++++++++++++++++ .../install/ThingsboardInstallService.java | 2 + .../DefaultSystemDataLoaderService.java | 1 + .../server/common/data/HomeDashboard.java | 30 +++++ .../server/common/data/HomeDashboardInfo.java | 27 +++++ ui-ngx/src/app/core/api/alias-controller.ts | 4 +- ui-ngx/src/app/core/guards/auth.guard.ts | 12 +- ui-ngx/src/app/core/http/dashboard.service.ts | 15 ++- ui-ngx/src/app/core/services/menu.service.ts | 7 ++ .../dashboard-widget-select.component.html | 5 + .../layout/dashboard-layout.component.html | 1 + .../dashboard/dashboard.component.html | 2 +- .../dashboard/dashboard.component.scss | 3 + .../dashboard/dashboard.component.ts | 3 + .../home/components/widget/lib/flot-widget.ts | 4 +- .../lib/navigation-card-widget.component.html | 21 ++++ .../lib/navigation-card-widget.component.scss | 60 +++++++++ .../lib/navigation-card-widget.component.ts | 66 ++++++++++ .../navigation-cards-widget.component.html | 37 ++++++ .../navigation-cards-widget.component.scss | 85 +++++++++++++ .../lib/navigation-cards-widget.component.ts | 114 ++++++++++++++++++ .../widget/widget-components.module.ts | 10 +- .../home/pages/admin/admin-routing.module.ts | 25 +++- .../modules/home/pages/admin/admin.module.ts | 4 +- .../pages/admin/home-settings.component.html | 54 +++++++++ .../pages/admin/home-settings.component.scss | 36 ++++++ .../pages/admin/home-settings.component.ts | 84 +++++++++++++ .../pages/customer/customer.component.html | 15 +++ .../pages/customer/customer.component.scss | 35 ++++++ .../home/pages/customer/customer.component.ts | 14 ++- .../home-links/home-links-routing.module.ts | 26 +++- .../home-links/home-links.component.html | 43 ++++--- .../home-links/home-links.component.scss | 5 + .../pages/home-links/home-links.component.ts | 17 ++- .../pages/home-links/home-links.module.ts | 2 + .../home/pages/profile/profile.component.html | 14 +++ .../home/pages/profile/profile.component.scss | 16 +++ .../home/pages/profile/profile.component.ts | 24 +++- .../home/pages/tenant/tenant.component.html | 15 +++ .../home/pages/tenant/tenant.component.scss | 35 ++++++ .../home/pages/tenant/tenant.component.ts | 13 +- .../home/pages/user/user.component.html | 14 +++ .../modules/home/pages/user/user.component.ts | 10 +- .../widget/widget-library.component.html | 1 + .../json-form/react/json-form-radios.tsx | 7 +- .../json-form/react/json-form-rc-select.tsx | 16 ++- .../src/app/shared/models/dashboard.models.ts | 9 ++ .../assets/locale/locale.constant-en_US.json | 5 +- ui-ngx/yarn.lock | 18 ++- 51 files changed, 1182 insertions(+), 84 deletions(-) create mode 100644 application/src/main/data/json/system/widget_bundles/navigation_widgets.json create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/HomeDashboard.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/HomeDashboardInfo.java create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/navigation-card-widget.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/navigation-card-widget.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/navigation-card-widget.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/navigation-cards-widget.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/navigation-cards-widget.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/navigation-cards-widget.component.ts create mode 100644 ui-ngx/src/app/modules/home/pages/admin/home-settings.component.html create mode 100644 ui-ngx/src/app/modules/home/pages/admin/home-settings.component.scss create mode 100644 ui-ngx/src/app/modules/home/pages/admin/home-settings.component.ts create mode 100644 ui-ngx/src/app/modules/home/pages/customer/customer.component.scss create mode 100644 ui-ngx/src/app/modules/home/pages/tenant/tenant.component.scss diff --git a/application/src/main/data/json/system/widget_bundles/charts.json b/application/src/main/data/json/system/widget_bundles/charts.json index 1010013689..140004c37c 100644 --- a/application/src/main/data/json/system/widget_bundles/charts.json +++ b/application/src/main/data/json/system/widget_bundles/charts.json @@ -25,22 +25,6 @@ "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = (prevValue-50) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+50;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#4caf50\",\"settings\":{},\"_hash\":0.545701115289893,\"funcBody\":\"var value = (prevValue-20) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+20;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Third\",\"color\":\"#f44336\",\"settings\":{},\"_hash\":0.2592906835158064,\"funcBody\":\"var value = (prevValue-40) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+40;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Fourth\",\"color\":\"#ffc107\",\"settings\":{},\"_hash\":0.12880275585455747,\"funcBody\":\"var value = (prevValue-50) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+50;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{},\"title\":\"Bars - Chart.js\"}" } }, - { - "alias": "basic_timeseries", - "name": "Timeseries - Flot", - "descriptor": { - "type": "timeseries", - "sizeX": 8, - "sizeY": 5, - "resources": [], - "templateHtml": "", - "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", - "controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx); \n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.getSettingsSchema = function() {\n return TbFlot.settingsSchema('graph');\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbFlot.datakeySettingsSchema(true, 'graph');\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n", - "settingsSchema": "{}", - "dataKeySettingsSchema": "{}", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"shadowSize\":4,\"fontColor\":\"#545454\",\"fontSize\":10,\"xaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"grid\":{\"color\":\"#545454\",\"tickColor\":\"#DDDDDD\",\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1},\"legend\":{\"show\":true,\"position\":\"nw\",\"backgroundColor\":\"#f0f0f0\",\"backgroundOpacity\":0.85,\"labelBoxBorderColor\":\"rgba(1, 1, 1, 0.45)\"},\"decimals\":1,\"stack\":false,\"tooltipIndividual\":false},\"title\":\"Timeseries - Flot\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null}" - } - }, { "alias": "doughnut_chart_js", "name": "Doughnut - Chart.js", @@ -71,7 +55,7 @@ "resources": [], "templateHtml": "", "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.pie-label {\n font-size: 12px;\n font-family: 'Roboto';\n font-weight: bold;\n text-align: center;\n padding: 2px;\n color: white;\n}\n", - "controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx, 'pie'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.getSettingsSchema = function() {\n return TbFlot.pieSettingsSchema();\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbFlot.pieDatakeySettingsSchema();\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\nself.actionSources = function() {\n return {\n 'sliceClick': {\n name: 'widget-action.pie-slice-click',\n multiple: false\n }\n };\n}\n", + "controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx, 'pie'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.getSettingsSchema = function() {\n return TbFlot.pieSettingsSchema();\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbFlot.pieDatakeySettingsSchema();\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\nself.actionSources = function() {\n return {\n 'sliceClick': {\n name: 'widget-action.pie-slice-click',\n multiple: false\n }\n };\n}\n", "settingsSchema": "{}\n", "dataKeySettingsSchema": "{}\n", "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = (prevValue-50) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+50;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#4caf50\",\"settings\":{},\"_hash\":0.6114638304362894,\"funcBody\":\"var value = (prevValue-20) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+20;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Third\",\"color\":\"#f44336\",\"settings\":{},\"_hash\":0.9955906536344441,\"funcBody\":\"var value = (prevValue-40) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+40;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Fourth\",\"color\":\"#ffc107\",\"settings\":{},\"_hash\":0.9430835931647599,\"funcBody\":\"var value = (prevValue-50) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+50;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"radius\":1,\"fontColor\":\"#545454\",\"fontSize\":10,\"decimals\":1,\"legend\":{\"show\":true,\"position\":\"nw\",\"labelBoxBorderColor\":\"#CCCCCC\",\"backgroundColor\":\"#F0F0F0\",\"backgroundOpacity\":0.85},\"innerRadius\":0,\"showLabels\":true,\"showPercentages\":true,\"stroke\":{\"width\":5},\"tilt\":1,\"animatedPie\":false},\"title\":\"Pie - Flot\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400}}" @@ -138,8 +122,8 @@ } }, { - "alias": "timeseries_bars_flot", - "name": "Timeseries Bars - Flot", + "alias": "state_chart", + "name": "State Chart", "descriptor": { "type": "timeseries", "sizeX": 8, @@ -147,15 +131,15 @@ "resources": [], "templateHtml": "", "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", - "controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx, 'bar'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.getSettingsSchema = function() {\n return TbFlot.settingsSchema('bar');\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbFlot.datakeySettingsSchema(false, 'bar');\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n", + "controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx, 'state'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.typeParameters = function() {\n return {\n stateData: true\n };\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.getSettingsSchema = function() {\n return TbFlot.settingsSchema('graph');\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbFlot.datakeySettingsSchema(true, 'graph');\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n", "settingsSchema": "{}", "dataKeySettingsSchema": "{}", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":false,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":false,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000},\"aggregation\":{\"limit\":200,\"type\":\"AVG\"}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"shadowSize\":4,\"fontColor\":\"#545454\",\"fontSize\":10,\"xaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"grid\":{\"color\":\"#545454\",\"tickColor\":\"#DDDDDD\",\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1},\"stack\":true,\"tooltipIndividual\":false,\"defaultBarWidth\":600},\"title\":\"Timeseries Bars - Flot\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":true,\"showLegend\":true,\"actions\":{}}" + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Switch 1\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false,\"axisPosition\":\"left\",\"showSeparateAxis\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"return Math.random() > 0.5 ? 1 : 0;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Switch 2\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false,\"axisPosition\":\"left\"},\"_hash\":0.12775350966079668,\"funcBody\":\"return Math.random() <= 0.5 ? 1 : 0;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"shadowSize\":4,\"fontColor\":\"#545454\",\"fontSize\":10,\"xaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"showLabels\":true,\"color\":\"#545454\",\"ticksFormatter\":\"if (value > 0 && value <= 1) {\\n return 'On';\\n} else if (value === 0) {\\n return 'Off';\\n} else {\\n return '';\\n}\"},\"grid\":{\"color\":\"#545454\",\"tickColor\":\"#DDDDDD\",\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1},\"stack\":false,\"tooltipIndividual\":false,\"tooltipValueFormatter\":\"if (value > 0 && value <= 1) {\\n return 'On';\\n} else if (value === 0) {\\n return 'Off';\\n} else {\\n return '';\\n}\",\"smoothLines\":false},\"title\":\"State Chart\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":true,\"showLegend\":true,\"actions\":{},\"legendConfig\":{\"direction\":\"column\",\",position\":\"bottom\",\"showMin\":false,\"showMax\":false,\"showAvg\":false,\"showTotal\":false}}" } }, { - "alias": "state_chart", - "name": "State Chart", + "alias": "basic_timeseries", + "name": "Timeseries - Flot", "descriptor": { "type": "timeseries", "sizeX": 8, @@ -163,11 +147,27 @@ "resources": [], "templateHtml": "", "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", - "controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx, 'state'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.typeParameters = function() {\n return {\n stateData: true\n };\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.getSettingsSchema = function() {\n return TbFlot.settingsSchema('graph');\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbFlot.datakeySettingsSchema(true, 'graph');\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n", + "controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx); \n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.getSettingsSchema = function() {\n return TbFlot.settingsSchema('graph');\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbFlot.datakeySettingsSchema(true, 'graph');\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n", "settingsSchema": "{}", "dataKeySettingsSchema": "{}", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Switch 1\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false,\"axisPosition\":\"left\",\"showSeparateAxis\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"return Math.random() > 0.5 ? 1 : 0;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Switch 2\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false,\"axisPosition\":\"left\"},\"_hash\":0.12775350966079668,\"funcBody\":\"return Math.random() <= 0.5 ? 1 : 0;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"shadowSize\":4,\"fontColor\":\"#545454\",\"fontSize\":10,\"xaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"showLabels\":true,\"color\":\"#545454\",\"ticksFormatter\":\"if (value > 0 && value <= 1) {\\n return 'On';\\n} else if (value === 0) {\\n return 'Off';\\n} else {\\n return '';\\n}\"},\"grid\":{\"color\":\"#545454\",\"tickColor\":\"#DDDDDD\",\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1},\"stack\":false,\"tooltipIndividual\":false,\"tooltipValueFormatter\":\"if (value > 0 && value <= 1) {\\n return 'On';\\n} else if (value === 0) {\\n return 'Off';\\n} else {\\n return '';\\n}\",\"smoothLines\":false},\"title\":\"State Chart\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":true,\"showLegend\":true,\"actions\":{},\"legendConfig\":{\"direction\":\"column\",\",position\":\"bottom\",\"showMin\":false,\"showMax\":false,\"showAvg\":false,\"showTotal\":false}}" + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"shadowSize\":4,\"fontColor\":\"#545454\",\"fontSize\":10,\"xaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"grid\":{\"color\":\"#545454\",\"tickColor\":\"#DDDDDD\",\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1},\"legend\":{\"show\":true,\"position\":\"nw\",\"backgroundColor\":\"#f0f0f0\",\"backgroundOpacity\":0.85,\"labelBoxBorderColor\":\"rgba(1, 1, 1, 0.45)\"},\"decimals\":1,\"stack\":false,\"tooltipIndividual\":false},\"title\":\"Timeseries - Flot\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null}" + } + }, + { + "alias": "timeseries_bars_flot", + "name": "Timeseries Bars - Flot", + "descriptor": { + "type": "timeseries", + "sizeX": 8, + "sizeY": 5, + "resources": [], + "templateHtml": "", + "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", + "controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx, 'bar'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.getSettingsSchema = function() {\n return TbFlot.settingsSchema('bar');\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbFlot.datakeySettingsSchema(false, 'bar');\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n", + "settingsSchema": "{}", + "dataKeySettingsSchema": "{}", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":false,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":false,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000},\"aggregation\":{\"limit\":200,\"type\":\"AVG\"}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"shadowSize\":4,\"fontColor\":\"#545454\",\"fontSize\":10,\"xaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"grid\":{\"color\":\"#545454\",\"tickColor\":\"#DDDDDD\",\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1},\"stack\":true,\"tooltipIndividual\":false,\"defaultBarWidth\":600},\"title\":\"Timeseries Bars - Flot\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":true,\"showLegend\":true,\"actions\":{}}" } } ] -} +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_bundles/navigation_widgets.json b/application/src/main/data/json/system/widget_bundles/navigation_widgets.json new file mode 100644 index 0000000000..c37e21906c --- /dev/null +++ b/application/src/main/data/json/system/widget_bundles/navigation_widgets.json @@ -0,0 +1,41 @@ +{ + "widgetsBundle": { + "alias": "navigation_widgets", + "title": "Navigation widgets", + "image": null + }, + "widgetTypes": [ + { + "alias": "navigation_cards", + "name": "Navigation cards", + "descriptor": { + "type": "static", + "sizeX": 7, + "sizeY": 6, + "resources": [], + "templateHtml": "", + "templateCss": "/*#widget-container {\n overflow-y: auto;\n box-sizing: content-box !important;\n cursor: auto;\n}*/\n\n#widget-container #container {\n overflow-y: auto;\n box-sizing: content-box;\n cursor: auto;\n}", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.navigationCardsWidget.resize();\n}\n\nself.onResize = function() {\n self.ctx.$scope.navigationCardsWidget.resize();\n}\n\nself.onDestroy = function() {\n}\n", + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"filterType\": {\n \"title\": \"Filter type\",\n \"type\": \"string\",\n \"default\": \"all\"\n },\n \"filter\": {\n \"title\": \"Items\",\n \"type\": \"array\"\n }\n },\n \"required\": []\n },\n \"form\": [\n {\n \"key\": \"filterType\",\n \"type\": \"radios\",\n \"direction\": \"row\",\n \"titleMap\": [\n {\n \"value\": \"all\",\n \"name\": \"All items\"\n },\n {\n \"value\": \"include\",\n \"name\": \"Include items\"\n },\n {\n \"value\": \"exclude\",\n \"name\": \"Exclude items\"\n }\n ]\n },\n {\n \"key\": \"filter\",\n \"type\": \"rc-select\",\n \"condition\": \"model.filterType !== 'all'\",\n \"tags\": true,\n \"placeholder\": \"Enter urls to filter\",\n \"items\": [{\"value\": \"/devices\", \"label\": \"/devices\"}, {\"value\": \"/assets\", \"label\": \"/assets\"}, {\"value\": \"/deviceProfies\", \"label\": \"/deviceProfies\"}]\n }\n ]\n}\n", + "dataKeySettingsSchema": "{}\n", + "defaultConfig": "{\"datasources\":[{\"type\":\"static\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(255,255,255,0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"filterType\":\"all\"},\"title\":\"Navigation cards\",\"dropShadow\":false,\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"showLegend\":false}" + } + }, + { + "alias": "navigation_card", + "name": "Navigation card", + "descriptor": { + "type": "static", + "sizeX": 2.5, + "sizeY": 2, + "resources": [], + "templateHtml": "", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n\n}\n\n\nself.onDestroy = function() {\n}\n", + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"name\": {\n \"title\": \"Title\",\n \"type\": \"string\",\n \"default\": \"{i18n:device.devices}\"\n },\n \"icon\": {\n \"title\": \"icon\",\n \"type\": \"string\",\n \"default\": \"devices_other\"\n },\n \"path\": {\n \"title\": \"Navigation path\",\n \"type\": \"string\",\n \"default\": \"/devices\"\n }\n },\n \"required\": [\"name\", \"icon\", \"path\"]\n },\n \"form\": [\n \"name\",\n {\n \"key\": \"icon\",\n \"type\": \"icon\"\n },\n \"path\"\n ]\n}\n", + "dataKeySettingsSchema": "{}\n", + "defaultConfig": "{\"datasources\":[{\"type\":\"static\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(255,255,255,0)\",\"color\":\"rgba(255,255,255,0.87)\",\"padding\":\"8px\",\"settings\":{\"name\":\"{i18n:device.devices}\",\"icon\":\"devices_other\",\"path\":\"/devices\"},\"title\":\"Navigation card\",\"dropShadow\":false,\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"showLegend\":false}" + } + } + ] +} \ No newline at end of file diff --git a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java index b6c040acdf..c780dde8a9 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java @@ -15,6 +15,8 @@ */ package org.thingsboard.server.controller; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; @@ -30,7 +32,11 @@ import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.DashboardInfo; import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.HomeDashboard; +import org.thingsboard.server.common.data.HomeDashboardInfo; import org.thingsboard.server.common.data.ShortCustomerInfo; +import org.thingsboard.server.common.data.Tenant; +import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.CustomerId; @@ -39,7 +45,9 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.TimePageLink; +import org.thingsboard.server.dao.util.mapping.JacksonUtil; import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Resource; @@ -53,6 +61,9 @@ public class DashboardController extends BaseController { public static final String DASHBOARD_ID = "dashboardId"; + private static final String HOME_DASHBOARD_ID = "homeDashboardId"; + private static final String HOME_DASHBOARD_HIDE_TOOLBAR = "homeDashboardHideToolbar"; + @Value("${dashboard.max_datapoints_limit}") private long maxDatapointsLimit; @@ -472,4 +483,100 @@ public class DashboardController extends BaseController { throw handleException(e); } } + + @PreAuthorize("isAuthenticated()") + @RequestMapping(value = "/dashboard/home", method = RequestMethod.GET) + @ResponseBody + public HomeDashboard getHomeDashboard() throws ThingsboardException { + try { + SecurityUser securityUser = getCurrentUser(); + if (securityUser.isSystemAdmin()) { + return null; + } + User user = userService.findUserById(securityUser.getTenantId(), securityUser.getId()); + JsonNode additionalInfo = user.getAdditionalInfo(); + HomeDashboard homeDashboard; + homeDashboard = extractHomeDashboardFromAdditionalInfo(additionalInfo); + if (homeDashboard == null) { + if (securityUser.isCustomerUser()) { + Customer customer = customerService.findCustomerById(securityUser.getTenantId(), securityUser.getCustomerId()); + additionalInfo = customer.getAdditionalInfo(); + homeDashboard = extractHomeDashboardFromAdditionalInfo(additionalInfo); + } + if (homeDashboard == null) { + Tenant tenant = tenantService.findTenantById(securityUser.getTenantId()); + additionalInfo = tenant.getAdditionalInfo(); + homeDashboard = extractHomeDashboardFromAdditionalInfo(additionalInfo); + } + } + return homeDashboard; + } catch (Exception e) { + throw handleException(e); + } + } + + @PreAuthorize("hasAuthority('TENANT_ADMIN')") + @RequestMapping(value = "/tenant/dashboard/home/info", method = RequestMethod.GET) + @ResponseBody + public HomeDashboardInfo getTenantHomeDashboardInfo() throws ThingsboardException { + try { + Tenant tenant = tenantService.findTenantById(getTenantId()); + JsonNode additionalInfo = tenant.getAdditionalInfo(); + DashboardId dashboardId = null; + boolean hideDashboardToolbar = true; + if (additionalInfo != null && additionalInfo.has(HOME_DASHBOARD_ID)) { + String strDashboardId = additionalInfo.get(HOME_DASHBOARD_ID).asText(); + dashboardId = new DashboardId(toUUID(strDashboardId)); + if (additionalInfo.has(HOME_DASHBOARD_HIDE_TOOLBAR)) { + hideDashboardToolbar = additionalInfo.get(HOME_DASHBOARD_HIDE_TOOLBAR).asBoolean(); + } + } + return new HomeDashboardInfo(dashboardId, hideDashboardToolbar); + } catch (Exception e) { + throw handleException(e); + } + } + + @PreAuthorize("hasAuthority('TENANT_ADMIN')") + @RequestMapping(value = "/tenant/dashboard/home/info", method = RequestMethod.POST) + @ResponseStatus(value = HttpStatus.OK) + public void setTenantHomeDashboardInfo(@RequestBody HomeDashboardInfo homeDashboardInfo) throws ThingsboardException { + try { + if (homeDashboardInfo.getDashboardId() != null) { + checkDashboardId(homeDashboardInfo.getDashboardId(), Operation.READ); + } + Tenant tenant = tenantService.findTenantById(getTenantId()); + JsonNode additionalInfo = tenant.getAdditionalInfo(); + if (additionalInfo == null || !(additionalInfo instanceof ObjectNode)) { + additionalInfo = JacksonUtil.OBJECT_MAPPER.createObjectNode(); + } + if (homeDashboardInfo.getDashboardId() != null) { + ((ObjectNode) additionalInfo).put(HOME_DASHBOARD_ID, homeDashboardInfo.getDashboardId().getId().toString()); + ((ObjectNode) additionalInfo).put(HOME_DASHBOARD_HIDE_TOOLBAR, homeDashboardInfo.isHideDashboardToolbar()); + } else { + ((ObjectNode) additionalInfo).remove(HOME_DASHBOARD_ID); + ((ObjectNode) additionalInfo).remove(HOME_DASHBOARD_HIDE_TOOLBAR); + } + tenant.setAdditionalInfo(additionalInfo); + tenantService.saveTenant(tenant); + } catch (Exception e) { + throw handleException(e); + } + } + + private HomeDashboard extractHomeDashboardFromAdditionalInfo(JsonNode additionalInfo) { + try { + if (additionalInfo != null && additionalInfo.has(HOME_DASHBOARD_ID)) { + String strDashboardId = additionalInfo.get(HOME_DASHBOARD_ID).asText(); + DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); + Dashboard dashboard = checkDashboardId(dashboardId, Operation.READ); + boolean hideDashboardToolbar = true; + if (additionalInfo.has(HOME_DASHBOARD_HIDE_TOOLBAR)) { + hideDashboardToolbar = additionalInfo.get(HOME_DASHBOARD_HIDE_TOOLBAR).asBoolean(); + } + return new HomeDashboard(dashboard, hideDashboardToolbar); + } + } catch (Exception e) {} + return null; + } } diff --git a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java index f22dcb0951..658c4a1fba 100644 --- a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java +++ b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java @@ -185,6 +185,8 @@ public class ThingsboardInstallService { case "3.2.0": log.info("Upgrading ThingsBoard from version 3.2.0 to 3.2.1 ..."); databaseEntitiesUpgradeService.upgradeDatabase("3.2.0"); + case "3.2.1": + log.info("Upgrading ThingsBoard from version 3.2.1 to 3.3.0 ..."); log.info("Updating system data..."); systemDataLoaderService.updateSystemWidgets(); break; diff --git a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java index 8bec74cff9..ac502926f8 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java @@ -438,6 +438,7 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { this.deleteSystemWidgetBundle("input_widgets"); this.deleteSystemWidgetBundle("date"); this.deleteSystemWidgetBundle("entity_admin_widgets"); + this.deleteSystemWidgetBundle("navigation_widgets"); installScripts.loadSystemWidgets(); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/HomeDashboard.java b/common/data/src/main/java/org/thingsboard/server/common/data/HomeDashboard.java new file mode 100644 index 0000000000..f2985e3371 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/HomeDashboard.java @@ -0,0 +1,30 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data; + +import lombok.Data; + +@Data +public class HomeDashboard extends Dashboard { + + private boolean hideDashboardToolbar; + + public HomeDashboard(Dashboard dashboard, boolean hideDashboardToolbar) { + super(dashboard); + this.hideDashboardToolbar = hideDashboardToolbar; + } + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/HomeDashboardInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/HomeDashboardInfo.java new file mode 100644 index 0000000000..1cbc1c737e --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/HomeDashboardInfo.java @@ -0,0 +1,27 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data; + +import lombok.AllArgsConstructor; +import lombok.Data; +import org.thingsboard.server.common.data.id.DashboardId; + +@Data +@AllArgsConstructor +public class HomeDashboardInfo { + private DashboardId dashboardId; + private boolean hideDashboardToolbar; +} diff --git a/ui-ngx/src/app/core/api/alias-controller.ts b/ui-ngx/src/app/core/api/alias-controller.ts index 8b2c8f0078..6ca208c506 100644 --- a/ui-ngx/src/app/core/api/alias-controller.ts +++ b/ui-ngx/src/app/core/api/alias-controller.ts @@ -53,8 +53,8 @@ export class AliasController implements IAliasController { private stateControllerHolder: StateControllerHolder, private origEntityAliases: EntityAliases, private origFilters: Filters) { - this.entityAliases = deepClone(this.origEntityAliases); - this.filters = deepClone(this.origFilters); + this.entityAliases = deepClone(this.origEntityAliases) || {}; + this.filters = deepClone(this.origFilters) || {}; this.userFilters = {}; } diff --git a/ui-ngx/src/app/core/guards/auth.guard.ts b/ui-ngx/src/app/core/guards/auth.guard.ts index 06a76e62e1..fdba07b94a 100644 --- a/ui-ngx/src/app/core/guards/auth.guard.ts +++ b/ui-ngx/src/app/core/guards/auth.guard.ts @@ -15,7 +15,7 @@ /// import { Injectable, NgZone } from '@angular/core'; -import { ActivatedRouteSnapshot, CanActivate, CanActivateChild, RouterStateSnapshot } from '@angular/router'; +import { ActivatedRouteSnapshot, CanActivate, CanActivateChild, Router, RouterStateSnapshot } from '@angular/router'; import { AuthService } from '../auth/auth.service'; import { select, Store } from '@ngrx/store'; import { AppState } from '../core.state'; @@ -28,6 +28,7 @@ import { Authority } from '@shared/models/authority.enum'; import { DialogService } from '@core/services/dialog.service'; import { TranslateService } from '@ngx-translate/core'; import { UtilsService } from '@core/services/utils.service'; +import { isObject } from '@core/utils'; @Injectable({ providedIn: 'root' @@ -35,6 +36,7 @@ import { UtilsService } from '@core/services/utils.service'; export class AuthGuard implements CanActivate, CanActivateChild { constructor(private store: Store, + private router: Router, private authService: AuthService, private dialogService: DialogService, private utils: UtilsService, @@ -115,6 +117,14 @@ export class AuthGuard implements CanActivate, CanActivateChild { if (data.auth && data.auth.indexOf(authority) === -1) { this.dialogService.forbidden(); return of(false); + } else if (data.redirectTo) { + let redirect; + if (isObject(data.redirectTo)) { + redirect = data.redirectTo[authority]; + } else { + redirect = data.redirectTo; + } + return of(this.router.parseUrl(redirect)); } else { return of(true); } diff --git a/ui-ngx/src/app/core/http/dashboard.service.ts b/ui-ngx/src/app/core/http/dashboard.service.ts index a1307bb080..3f3e512752 100644 --- a/ui-ngx/src/app/core/http/dashboard.service.ts +++ b/ui-ngx/src/app/core/http/dashboard.service.ts @@ -20,7 +20,7 @@ import { Observable } from 'rxjs'; import { HttpClient } from '@angular/common/http'; import { PageLink } from '@shared/models/page/page-link'; import { PageData } from '@shared/models/page/page-data'; -import { Dashboard, DashboardInfo } from '@shared/models/dashboard.models'; +import { Dashboard, DashboardInfo, HomeDashboard, HomeDashboardInfo } from '@shared/models/dashboard.models'; import { WINDOW } from '@core/services/window.service'; import { NavigationEnd, Router } from '@angular/router'; import { filter, map, publishReplay, refCount } from 'rxjs/operators'; @@ -122,6 +122,19 @@ export class DashboardService { defaultHttpOptionsFromConfig(config)); } + public getHomeDashboard(config?: RequestConfig): Observable { + return this.http.get('/api/dashboard/home', defaultHttpOptionsFromConfig(config)); + } + + public getTenantHomeDashboardInfo(config?: RequestConfig): Observable { + return this.http.get('/api/tenant/dashboard/home/info', defaultHttpOptionsFromConfig(config)); + } + + public setTenantHomeDashboardInfo(homeDashboardInfo: HomeDashboardInfo, config?: RequestConfig): Observable { + return this.http.post('/api/tenant/dashboard/home/info', homeDashboardInfo, + defaultHttpOptionsFromConfig(config)); + } + public getPublicDashboardLink(dashboard: DashboardInfo): string | null { if (dashboard && dashboard.assignedCustomers && dashboard.assignedCustomers.length > 0) { const publicCustomers = dashboard.assignedCustomers diff --git a/ui-ngx/src/app/core/services/menu.service.ts b/ui-ngx/src/app/core/services/menu.service.ts index 98b3b9de1e..735fd6bead 100644 --- a/ui-ngx/src/app/core/services/menu.service.ts +++ b/ui-ngx/src/app/core/services/menu.service.ts @@ -282,6 +282,13 @@ export class MenuService { path: '/dashboards', icon: 'dashboards' }, + { + id: guid(), + name: 'admin.home-settings', + type: 'link', + path: '/settings/home', + icon: 'settings_applications' + }, { id: guid(), name: 'audit-log.audit-logs', diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.html b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.html index 43f9ca4a3f..a095dae071 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.html +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.html @@ -23,6 +23,7 @@ [widgetLayouts]="{}" [isEdit]="false" [isMobile]="true" + [disableWidgetInteraction]="true" [isEditActionEnabled]="false" [isExportActionEnabled]="false" [isRemoveActionEnabled]="false" @@ -34,6 +35,7 @@ [widgetLayouts]="{}" [isEdit]="false" [isMobile]="true" + [disableWidgetInteraction]="true" [isEditActionEnabled]="false" [isExportActionEnabled]="false" [isRemoveActionEnabled]="false" @@ -45,6 +47,7 @@ [widgetLayouts]="{}" [isEdit]="false" [isMobile]="true" + [disableWidgetInteraction]="true" [isEditActionEnabled]="false" [isExportActionEnabled]="false" [isRemoveActionEnabled]="false" @@ -56,6 +59,7 @@ [widgetLayouts]="{}" [isEdit]="false" [isMobile]="true" + [disableWidgetInteraction]="true" [isEditActionEnabled]="false" [isExportActionEnabled]="false" [isRemoveActionEnabled]="false" @@ -67,6 +71,7 @@ [widgetLayouts]="{}" [isEdit]="false" [isMobile]="true" + [disableWidgetInteraction]="true" [isEditActionEnabled]="false" [isExportActionEnabled]="false" [isRemoveActionEnabled]="false" diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/layout/dashboard-layout.component.html b/ui-ngx/src/app/modules/home/components/dashboard-page/layout/dashboard-layout.component.html index 7f1097444f..061a4d5227 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/layout/dashboard-layout.component.html +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/layout/dashboard-layout.component.html @@ -53,6 +53,7 @@ [mobileRowHeight]="layoutCtx.gridSettings.mobileRowHeight" [isMobile]="isMobile" [isMobileDisabled]="widgetEditMode" + [disableWidgetInteraction]="isEdit" [isEditActionEnabled]="isEdit" [isExportActionEnabled]="isEdit && !widgetEditMode" [isRemoveActionEnabled]="isEdit && !widgetEditMode" diff --git a/ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.html b/ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.html index b472ca54cc..bd675a0a9f 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.html +++ b/ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.html @@ -150,7 +150,7 @@ -
+
+ + {{settings.icon}} + {{translatedName}} + diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/navigation-card-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/navigation-card-widget.component.scss new file mode 100644 index 0000000000..18a81aa216 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/navigation-card-widget.component.scss @@ -0,0 +1,60 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +:host { + width: 100%; + height: 100%; +} + +:host ::ng-deep { + .tb-nav-button { + width: 100%; + height: 100%; + &:hover { + border-bottom: none; + } + &:focus { + border-bottom: none; + } + .mat-button-wrapper { + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + align-items: center; + mat-icon { + margin: auto; + } + span { + height: 18px; + min-height: 36px; + max-height: 36px; + padding: 0 0 20px 0; + margin: auto; + font-size: 18px; + font-weight: 400; + line-height: 18px; + white-space: normal; + } + } + &.mat-raised-button.mat-primary { + .mat-ripple-element { + opacity: 0.3; + background-color: rgba(255, 255, 255, 0.3); + } + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/navigation-card-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/navigation-card-widget.component.ts new file mode 100644 index 0000000000..5dbd8022ce --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/navigation-card-widget.component.ts @@ -0,0 +1,66 @@ +/// +/// Copyright © 2016-2021 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { PageComponent } from '@shared/components/page.component'; +import { Component, Input, NgZone, OnInit } from '@angular/core'; +import { WidgetContext } from '@home/models/widget-component.models'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { Router } from '@angular/router'; +import { UtilsService } from '@core/services/utils.service'; + +interface NavigationCardWidgetSettings { + name: string; + icon: string; + path: string; +} + +@Component({ + selector: 'tb-navigation-card-widget', + templateUrl: './navigation-card-widget.component.html', + styleUrls: ['./navigation-card-widget.component.scss'] +}) +export class NavigationCardWidgetComponent extends PageComponent implements OnInit { + + settings: NavigationCardWidgetSettings; + + translatedName: string; + + @Input() + ctx: WidgetContext; + + constructor(protected store: Store, + private utils: UtilsService, + private ngZone: NgZone, + private router: Router) { + super(store); + } + + ngOnInit(): void { + this.ctx.$scope.navigationCardWidget = this; + this.settings = this.ctx.settings; + this.translatedName = this.utils.customTranslation(this.settings.name, this.settings.name); + } + + + navigate($event: Event, path: string) { + $event.preventDefault(); + this.ngZone.run(() => { + this.router.navigateByUrl(path); + }); + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/navigation-cards-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/navigation-cards-widget.component.html new file mode 100644 index 0000000000..a9ed8e76bb --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/navigation-cards-widget.component.html @@ -0,0 +1,37 @@ + + + + + + {{section.name}} + + + + + + {{place.icon}} + + {{place.name}} + + + + + + + diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/navigation-cards-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/navigation-cards-widget.component.scss new file mode 100644 index 0000000000..6a0e60c20b --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/navigation-cards-widget.component.scss @@ -0,0 +1,85 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@import '../../../../../../scss/constants'; + +:host { + width: 100%; + height: 100%; +} + +:host ::ng-deep { + .tb-navigation-cards { + .mat-headline { + font-size: 20px; + @media #{$mat-gt-xmd} { + font-size: 24px; + } + } + mat-card { + padding: 0; + margin: 8px; + mat-card-title { + margin: 0; + padding: 24px 16px 16px; + } + mat-card-title+mat-card-content { + padding-top: 0; + } + mat-card-content { + padding: 16px; + } + } + .tb-card-button { + width: 100%; + height: 100%; + max-width: 240px; + &:hover { + border-bottom: none; + } + &:focus { + border-bottom: none; + } + .mat-button-wrapper { + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + align-items: center; + mat-icon { + margin: auto; + } + span { + height: 18px; + min-height: 36px; + max-height: 36px; + padding: 0 0 20px 0; + margin: auto; + font-size: 18px; + font-weight: 400; + line-height: 18px; + white-space: normal; + } + } + &.mat-raised-button.mat-primary { + .mat-ripple-element { + opacity: 0.3; + background-color: rgba(255, 255, 255, 0.3); + } + } + } + } +} + diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/navigation-cards-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/navigation-cards-widget.component.ts new file mode 100644 index 0000000000..7628c30457 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/navigation-cards-widget.component.ts @@ -0,0 +1,114 @@ +/// +/// Copyright © 2016-2021 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { PageComponent } from '@shared/components/page.component'; +import { Component, Input, NgZone, OnInit } from '@angular/core'; +import { WidgetContext } from '@home/models/widget-component.models'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { MenuService } from '@core/services/menu.service'; +import { HomeSection, HomeSectionPlace } from '@core/services/menu.models'; +import { Router } from '@angular/router'; +import { map } from 'rxjs/operators'; + +interface NavigationCardsWidgetSettings { + filterType: 'all' | 'include' | 'exclude'; + filter: string[]; +} + +@Component({ + selector: 'tb-navigation-cards-widget', + templateUrl: './navigation-cards-widget.component.html', + styleUrls: ['./navigation-cards-widget.component.scss'] +}) +export class NavigationCardsWidgetComponent extends PageComponent implements OnInit { + + homeSections$ = this.menuService.homeSections(); + showHomeSections$ = this.homeSections$.pipe( + map((sections) => { + return sections.filter((section) => this.sectionPlaces(section).length > 0); + }) + ); + + cols = null; + + settings: NavigationCardsWidgetSettings; + + @Input() + ctx: WidgetContext; + + constructor(protected store: Store, + private menuService: MenuService, + private ngZone: NgZone, + private router: Router) { + super(store); + } + + ngOnInit(): void { + this.ctx.$scope.navigationCardsWidget = this; + this.settings = this.ctx.settings; + } + + resize() { + this.updateColumnCount(); + } + + private updateColumnCount() { + this.cols = 2; + const width = this.ctx.width; + if (width >= 1280) { + this.cols = 3; + if (width >= 1920) { + this.cols = 4; + } + } + this.ctx.detectChanges(); + } + + navigate($event: Event, path: string) { + $event.preventDefault(); + this.ngZone.run(() => { + this.router.navigateByUrl(path); + }); + } + + sectionPlaces(section: HomeSection): HomeSectionPlace[] { + return section && section.places ? section.places.filter((place) => this.filterPlace(place)) : []; + } + + private filterPlace(place: HomeSectionPlace): boolean { + if (this.settings.filterType === 'include') { + return this.settings.filter.includes(place.path); + } else if (this.settings.filterType === 'exclude') { + return !this.settings.filter.includes(place.path); + } + return true; + } + + sectionColspan(section: HomeSection): number { + if (this.ctx.width >= 960) { + let colspan = this.cols; + const places = this.sectionPlaces(section); + if (places.length <= colspan) { + colspan = places.length; + } + return colspan; + } else { + return 2; + } + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts b/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts index 0c143f2b57..2d080bc8e9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts @@ -35,6 +35,8 @@ import { TripAnimationComponent } from './trip-animation/trip-animation.componen import { PhotoCameraInputWidgetComponent } from './lib/photo-camera-input.component'; import { GatewayFormComponent } from './lib/gateway/gateway-form.component'; import { ImportExportService } from '@home/components/import-export/import-export.service'; +import { NavigationCardsWidgetComponent } from '@home/components/widget/lib/navigation-cards-widget.component'; +import { NavigationCardWidgetComponent } from '@home/components/widget/lib/navigation-card-widget.component'; @NgModule({ declarations: @@ -50,7 +52,9 @@ import { ImportExportService } from '@home/components/import-export/import-expor MultipleInputWidgetComponent, TripAnimationComponent, PhotoCameraInputWidgetComponent, - GatewayFormComponent + GatewayFormComponent, + NavigationCardsWidgetComponent, + NavigationCardWidgetComponent ], imports: [ CommonModule, @@ -68,7 +72,9 @@ import { ImportExportService } from '@home/components/import-export/import-expor MultipleInputWidgetComponent, TripAnimationComponent, PhotoCameraInputWidgetComponent, - GatewayFormComponent + GatewayFormComponent, + NavigationCardsWidgetComponent, + NavigationCardWidgetComponent ], providers: [ CustomDialogService, diff --git a/ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts b/ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts index 1df4aed59e..1928a1f404 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts @@ -32,6 +32,7 @@ import { getCurrentAuthUser } from '@core/auth/auth.selectors'; import { OAuth2Service } from '@core/http/oauth2.service'; import { UserProfileResolver } from '@home/pages/profile/profile-routing.module'; import { SmsProviderComponent } from '@home/pages/admin/sms-provider.component'; +import { HomeSettingsComponent } from '@home/pages/admin/home-settings.component'; @Injectable() export class OAuth2LoginProcessingUrlResolver implements Resolve { @@ -48,7 +49,7 @@ const routes: Routes = [ { path: 'settings', data: { - auth: [Authority.SYS_ADMIN], + auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN], breadcrumb: { label: 'admin.system-settings', icon: 'settings' @@ -57,8 +58,13 @@ const routes: Routes = [ children: [ { path: '', - redirectTo: 'general', - pathMatch: 'full' + data: { + auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN], + redirectTo: { + SYS_ADMIN: '/settings/general', + TENANT_ADMIN: '/settings/home' + } + } }, { path: 'general', @@ -127,6 +133,19 @@ const routes: Routes = [ resolve: { loginProcessingUrl: OAuth2LoginProcessingUrlResolver } + }, + { + path: 'home', + component: HomeSettingsComponent, + canDeactivate: [ConfirmOnExitGuard], + data: { + auth: [Authority.TENANT_ADMIN], + title: 'admin.home-settings', + breadcrumb: { + label: 'admin.home-settings', + icon: 'settings_applications' + } + } } ] } diff --git a/ui-ngx/src/app/modules/home/pages/admin/admin.module.ts b/ui-ngx/src/app/modules/home/pages/admin/admin.module.ts index a170ce10b4..1671220cfe 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/admin.module.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/admin.module.ts @@ -26,6 +26,7 @@ import { HomeComponentsModule } from '@modules/home/components/home-components.m import { OAuth2SettingsComponent } from '@modules/home/pages/admin/oauth2-settings.component'; import { SmsProviderComponent } from '@home/pages/admin/sms-provider.component'; import { SendTestSmsDialogComponent } from '@home/pages/admin/send-test-sms-dialog.component'; +import { HomeSettingsComponent } from '@home/pages/admin/home-settings.component'; @NgModule({ declarations: @@ -35,7 +36,8 @@ import { SendTestSmsDialogComponent } from '@home/pages/admin/send-test-sms-dial SmsProviderComponent, SendTestSmsDialogComponent, SecuritySettingsComponent, - OAuth2SettingsComponent + OAuth2SettingsComponent, + HomeSettingsComponent ], imports: [ CommonModule, diff --git a/ui-ngx/src/app/modules/home/pages/admin/home-settings.component.html b/ui-ngx/src/app/modules/home/pages/admin/home-settings.component.html new file mode 100644 index 0000000000..0191724a24 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/admin/home-settings.component.html @@ -0,0 +1,54 @@ + +
+ + +
+ admin.home-settings +
+
+ + +
+ +
+
+
+
+ + + {{ 'dashboard.home-dashboard-hide-toolbar' | translate }} + +
+
+
+ +
+
+
+
+
+
diff --git a/ui-ngx/src/app/modules/home/pages/admin/home-settings.component.scss b/ui-ngx/src/app/modules/home/pages/admin/home-settings.component.scss new file mode 100644 index 0000000000..482889cf77 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/admin/home-settings.component.scss @@ -0,0 +1,36 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import "../../../../../scss/constants"; + +:host { + .tb-default-dashboard { + tb-dashboard-autocomplete { + @media #{$mat-gt-sm} { + padding-right: 12px; + } + + @media #{$mat-lt-md} { + padding-bottom: 12px; + } + } + mat-checkbox { + @media #{$mat-gt-sm} { + margin-top: 16px; + } + } + } +} diff --git a/ui-ngx/src/app/modules/home/pages/admin/home-settings.component.ts b/ui-ngx/src/app/modules/home/pages/admin/home-settings.component.ts new file mode 100644 index 0000000000..a92579d701 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/admin/home-settings.component.ts @@ -0,0 +1,84 @@ +/// +/// Copyright © 2016-2021 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component, OnInit } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { PageComponent } from '@shared/components/page.component'; +import { Router } from '@angular/router'; +import { FormBuilder, FormGroup } from '@angular/forms'; +import { HasConfirmForm } from '@core/guards/confirm-on-exit.guard'; +import { DashboardService } from '@core/http/dashboard.service'; +import { HomeDashboardInfo } from '@shared/models/dashboard.models'; +import { isDefinedAndNotNull } from '@core/utils'; +import { DashboardId } from '@shared/models/id/dashboard-id'; + +@Component({ + selector: 'tb-home-settings', + templateUrl: './home-settings.component.html', + styleUrls: ['./home-settings.component.scss', './settings-card.scss'] +}) +export class HomeSettingsComponent extends PageComponent implements OnInit, HasConfirmForm { + + homeSettings: FormGroup; + + constructor(protected store: Store, + private router: Router, + private dashboardService: DashboardService, + public fb: FormBuilder) { + super(store); + } + + ngOnInit() { + this.homeSettings = this.fb.group({ + dashboardId: [null], + hideDashboardToolbar: [true] + }); + this.dashboardService.getTenantHomeDashboardInfo().subscribe( + (homeDashboardInfo) => { + this.setHomeDashboardInfo(homeDashboardInfo); + } + ); + } + + save(): void { + const strDashboardId = this.homeSettings.get('dashboardId').value; + const dashboardId: DashboardId = strDashboardId ? new DashboardId(strDashboardId) : null; + const hideDashboardToolbar = this.homeSettings.get('hideDashboardToolbar').value; + const homeDashboardInfo: HomeDashboardInfo = { + dashboardId, + hideDashboardToolbar + }; + this.dashboardService.setTenantHomeDashboardInfo(homeDashboardInfo).subscribe( + () => { + this.setHomeDashboardInfo(homeDashboardInfo); + } + ); + } + + confirmForm(): FormGroup { + return this.homeSettings; + } + + private setHomeDashboardInfo(homeDashboardInfo: HomeDashboardInfo) { + this.homeSettings.reset({ + dashboardId: homeDashboardInfo?.dashboardId?.id, + hideDashboardToolbar: isDefinedAndNotNull(homeDashboardInfo?.hideDashboardToolbar) ? + homeDashboardInfo?.hideDashboardToolbar : true + }); + } + +} diff --git a/ui-ngx/src/app/modules/home/pages/customer/customer.component.html b/ui-ngx/src/app/modules/home/pages/customer/customer.component.html index fce5c1926c..392ae7b6c4 100644 --- a/ui-ngx/src/app/modules/home/pages/customer/customer.component.html +++ b/ui-ngx/src/app/modules/home/pages/customer/customer.component.html @@ -72,6 +72,21 @@ customer.description +
+
+ + + {{ 'dashboard.home-dashboard-hide-toolbar' | translate }} + +
+
diff --git a/ui-ngx/src/app/modules/home/pages/customer/customer.component.scss b/ui-ngx/src/app/modules/home/pages/customer/customer.component.scss new file mode 100644 index 0000000000..3a4ec550cd --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/customer/customer.component.scss @@ -0,0 +1,35 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@import "../../../../../scss/constants"; + +:host { + .tb-default-dashboard { + tb-dashboard-autocomplete { + @media #{$mat-gt-sm} { + padding-right: 12px; + } + + @media #{$mat-lt-md} { + padding-bottom: 12px; + } + } + mat-checkbox { + @media #{$mat-gt-sm} { + margin-top: 16px; + } + } + } +} diff --git a/ui-ngx/src/app/modules/home/pages/customer/customer.component.ts b/ui-ngx/src/app/modules/home/pages/customer/customer.component.ts index 809beef5cd..8c609fe2ef 100644 --- a/ui-ngx/src/app/modules/home/pages/customer/customer.component.ts +++ b/ui-ngx/src/app/modules/home/pages/customer/customer.component.ts @@ -23,10 +23,12 @@ import { ActionNotificationShow } from '@app/core/notification/notification.acti import { TranslateService } from '@ngx-translate/core'; import { ContactBasedComponent } from '../../components/entity/contact-based.component'; import { EntityTableConfig } from '@home/models/entity/entities-table-config.models'; +import { isDefinedAndNotNull } from '@core/utils'; @Component({ selector: 'tb-customer', - templateUrl: './customer.component.html' + templateUrl: './customer.component.html', + styleUrls: ['./customer.component.scss'] }) export class CustomerComponent extends ContactBasedComponent { @@ -54,7 +56,10 @@ export class CustomerComponent extends ContactBasedComponent { title: [entity ? entity.title : '', [Validators.required]], additionalInfo: this.fb.group( { - description: [entity && entity.additionalInfo ? entity.additionalInfo.description : ''] + description: [entity && entity.additionalInfo ? entity.additionalInfo.description : ''], + homeDashboardId: [entity && entity.additionalInfo ? entity.additionalInfo.homeDashboardId : null], + homeDashboardHideToolbar: [entity && entity.additionalInfo && + isDefinedAndNotNull(entity.additionalInfo.homeDashboardHideToolbar) ? entity.additionalInfo.homeDashboardHideToolbar : true] } ) } @@ -65,6 +70,11 @@ export class CustomerComponent extends ContactBasedComponent { this.isPublic = entity.additionalInfo && entity.additionalInfo.isPublic; this.entityForm.patchValue({title: entity.title}); this.entityForm.patchValue({additionalInfo: {description: entity.additionalInfo ? entity.additionalInfo.description : ''}}); + this.entityForm.patchValue({additionalInfo: + {homeDashboardId: entity.additionalInfo ? entity.additionalInfo.homeDashboardId : null}}); + this.entityForm.patchValue({additionalInfo: + {homeDashboardHideToolbar: entity.additionalInfo && + isDefinedAndNotNull(entity.additionalInfo.homeDashboardHideToolbar) ? entity.additionalInfo.homeDashboardHideToolbar : true}}); } onCustomerIdCopied(event) { diff --git a/ui-ngx/src/app/modules/home/pages/home-links/home-links-routing.module.ts b/ui-ngx/src/app/modules/home/pages/home-links/home-links-routing.module.ts index c1aa7764f0..003ba5d34a 100644 --- a/ui-ngx/src/app/modules/home/pages/home-links/home-links-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/home-links/home-links-routing.module.ts @@ -14,11 +14,25 @@ /// limitations under the License. /// -import { NgModule } from '@angular/core'; -import { RouterModule, Routes } from '@angular/router'; +import { Injectable, NgModule } from '@angular/core'; +import { Resolve, RouterModule, Routes } from '@angular/router'; import { HomeLinksComponent } from './home-links.component'; import { Authority } from '@shared/models/authority.enum'; +import { Observable } from 'rxjs'; +import { HomeDashboard } from '@shared/models/dashboard.models'; +import { DashboardService } from '@core/http/dashboard.service'; + +@Injectable() +export class HomeDashboardResolver implements Resolve { + + constructor(private dashboardService: DashboardService) { + } + + resolve(): Observable { + return this.dashboardService.getHomeDashboard(); + } +} const routes: Routes = [ { @@ -31,12 +45,18 @@ const routes: Routes = [ label: 'home.home', icon: 'home' } + }, + resolve: { + homeDashboard: HomeDashboardResolver } } ]; @NgModule({ imports: [RouterModule.forChild(routes)], - exports: [RouterModule] + exports: [RouterModule], + providers: [ + HomeDashboardResolver + ] }) export class HomeLinksRoutingModule { } diff --git a/ui-ngx/src/app/modules/home/pages/home-links/home-links.component.html b/ui-ngx/src/app/modules/home/pages/home-links/home-links.component.html index 85b5b388a7..f519d22637 100644 --- a/ui-ngx/src/app/modules/home/pages/home-links/home-links.component.html +++ b/ui-ngx/src/app/modules/home/pages/home-links/home-links.component.html @@ -15,23 +15,26 @@ limitations under the License. --> - - - - - {{section.name}} - - - - - - {{place.icon}} - - {{place.name}} - - - - - - - + + + + + + + {{section.name}} + + + + + + {{place.icon}} + + {{place.name}} + + + + + + + + diff --git a/ui-ngx/src/app/modules/home/pages/home-links/home-links.component.scss b/ui-ngx/src/app/modules/home/pages/home-links/home-links.component.scss index a97e7083e0..20949642ab 100644 --- a/ui-ngx/src/app/modules/home/pages/home-links/home-links.component.scss +++ b/ui-ngx/src/app/modules/home/pages/home-links/home-links.component.scss @@ -15,6 +15,11 @@ */ @import '../../../../../scss/constants'; +:host { + width: 100%; + height: 100%; +} + :host ::ng-deep { .tb-home-links { .mat-headline { diff --git a/ui-ngx/src/app/modules/home/pages/home-links/home-links.component.ts b/ui-ngx/src/app/modules/home/pages/home-links/home-links.component.ts index 7d5348c04f..7f485df45c 100644 --- a/ui-ngx/src/app/modules/home/pages/home-links/home-links.component.ts +++ b/ui-ngx/src/app/modules/home/pages/home-links/home-links.component.ts @@ -19,6 +19,8 @@ import { MenuService } from '@core/services/menu.service'; import { BreakpointObserver, BreakpointState } from '@angular/cdk/layout'; import { MediaBreakpoints } from '@shared/models/constants'; import { HomeSection } from '@core/services/menu.models'; +import { ActivatedRoute } from '@angular/router'; +import { HomeDashboard } from '@shared/models/dashboard.models'; @Component({ selector: 'tb-home-links', @@ -31,15 +33,20 @@ export class HomeLinksComponent implements OnInit { cols = 2; + homeDashboard: HomeDashboard = this.route.snapshot.data.homeDashboard; + constructor(private menuService: MenuService, - public breakpointObserver: BreakpointObserver) { + public breakpointObserver: BreakpointObserver, + private route: ActivatedRoute) { } ngOnInit() { - this.updateColumnCount(); - this.breakpointObserver - .observe([MediaBreakpoints.lg, MediaBreakpoints['gt-lg']]) - .subscribe((state: BreakpointState) => this.updateColumnCount()); + if (!this.homeDashboard) { + this.updateColumnCount(); + this.breakpointObserver + .observe([MediaBreakpoints.lg, MediaBreakpoints['gt-lg']]) + .subscribe((state: BreakpointState) => this.updateColumnCount()); + } } private updateColumnCount() { diff --git a/ui-ngx/src/app/modules/home/pages/home-links/home-links.module.ts b/ui-ngx/src/app/modules/home/pages/home-links/home-links.module.ts index e64b9b1768..644645c1a9 100644 --- a/ui-ngx/src/app/modules/home/pages/home-links/home-links.module.ts +++ b/ui-ngx/src/app/modules/home/pages/home-links/home-links.module.ts @@ -20,6 +20,7 @@ import { CommonModule } from '@angular/common'; import { HomeLinksRoutingModule } from './home-links-routing.module'; import { HomeLinksComponent } from './home-links.component'; import { SharedModule } from '@app/shared/shared.module'; +import { HomeComponentsModule } from '@home/components/home-components.module'; @NgModule({ declarations: @@ -29,6 +30,7 @@ import { SharedModule } from '@app/shared/shared.module'; imports: [ CommonModule, SharedModule, + HomeComponentsModule, HomeLinksRoutingModule ] }) diff --git a/ui-ngx/src/app/modules/home/pages/profile/profile.component.html b/ui-ngx/src/app/modules/home/pages/profile/profile.component.html index 7ab52a373a..eaca7133a0 100644 --- a/ui-ngx/src/app/modules/home/pages/profile/profile.component.html +++ b/ui-ngx/src/app/modules/home/pages/profile/profile.component.html @@ -63,6 +63,20 @@ +
+ + + {{ 'dashboard.home-dashboard-hide-toolbar' | translate }} + +
diff --git a/ui-ngx/src/app/modules/home/pages/tenant/tenant.component.scss b/ui-ngx/src/app/modules/home/pages/tenant/tenant.component.scss new file mode 100644 index 0000000000..3a4ec550cd --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/tenant/tenant.component.scss @@ -0,0 +1,35 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@import "../../../../../scss/constants"; + +:host { + .tb-default-dashboard { + tb-dashboard-autocomplete { + @media #{$mat-gt-sm} { + padding-right: 12px; + } + + @media #{$mat-lt-md} { + padding-bottom: 12px; + } + } + mat-checkbox { + @media #{$mat-gt-sm} { + margin-top: 16px; + } + } + } +} diff --git a/ui-ngx/src/app/modules/home/pages/tenant/tenant.component.ts b/ui-ngx/src/app/modules/home/pages/tenant/tenant.component.ts index a24a17e6bf..30c0dc36aa 100644 --- a/ui-ngx/src/app/modules/home/pages/tenant/tenant.component.ts +++ b/ui-ngx/src/app/modules/home/pages/tenant/tenant.component.ts @@ -23,11 +23,12 @@ import { ActionNotificationShow } from '@app/core/notification/notification.acti import { TranslateService } from '@ngx-translate/core'; import { ContactBasedComponent } from '../../components/entity/contact-based.component'; import { EntityTableConfig } from '@home/models/entity/entities-table-config.models'; +import { isDefinedAndNotNull } from '@core/utils'; @Component({ selector: 'tb-tenant', templateUrl: './tenant.component.html', - styleUrls: [] + styleUrls: ['./tenant.component.scss'] }) export class TenantComponent extends ContactBasedComponent { @@ -54,7 +55,10 @@ export class TenantComponent extends ContactBasedComponent { tenantProfileId: [entity ? entity.tenantProfileId : null, [Validators.required]], additionalInfo: this.fb.group( { - description: [entity && entity.additionalInfo ? entity.additionalInfo.description : ''] + description: [entity && entity.additionalInfo ? entity.additionalInfo.description : ''], + homeDashboardId: [entity && entity.additionalInfo ? entity.additionalInfo.homeDashboardId : null], + homeDashboardHideToolbar: [entity && entity.additionalInfo && + isDefinedAndNotNull(entity.additionalInfo.homeDashboardHideToolbar) ? entity.additionalInfo.homeDashboardHideToolbar : true] } ) } @@ -65,6 +69,11 @@ export class TenantComponent extends ContactBasedComponent { this.entityForm.patchValue({title: entity.title}); this.entityForm.patchValue({tenantProfileId: entity.tenantProfileId}); this.entityForm.patchValue({additionalInfo: {description: entity.additionalInfo ? entity.additionalInfo.description : ''}}); + this.entityForm.patchValue({additionalInfo: + {homeDashboardId: entity.additionalInfo ? entity.additionalInfo.homeDashboardId : null}}); + this.entityForm.patchValue({additionalInfo: + {homeDashboardHideToolbar: entity.additionalInfo && + isDefinedAndNotNull(entity.additionalInfo.homeDashboardHideToolbar) ? entity.additionalInfo.homeDashboardHideToolbar : true}}); } updateFormState() { diff --git a/ui-ngx/src/app/modules/home/pages/user/user.component.html b/ui-ngx/src/app/modules/home/pages/user/user.component.html index fbc5f3c1c7..20821031b0 100644 --- a/ui-ngx/src/app/modules/home/pages/user/user.component.html +++ b/ui-ngx/src/app/modules/home/pages/user/user.component.html @@ -95,6 +95,20 @@ {{ 'user.always-fullscreen' | translate }}
+
+ + + {{ 'dashboard.home-dashboard-hide-toolbar' | translate }} + +
diff --git a/ui-ngx/src/app/modules/home/pages/user/user.component.ts b/ui-ngx/src/app/modules/home/pages/user/user.component.ts index 585723b659..b9326a696f 100644 --- a/ui-ngx/src/app/modules/home/pages/user/user.component.ts +++ b/ui-ngx/src/app/modules/home/pages/user/user.component.ts @@ -23,7 +23,7 @@ import { User } from '@shared/models/user.model'; import { selectAuth } from '@core/auth/auth.selectors'; import { map } from 'rxjs/operators'; import { Authority } from '@shared/models/authority.enum'; -import { isUndefined } from '@core/utils'; +import { isDefinedAndNotNull, isUndefined } from '@core/utils'; import { EntityTableConfig } from '@home/models/entity/entities-table-config.models'; @Component({ @@ -74,6 +74,9 @@ export class UserComponent extends EntityComponent { description: [entity && entity.additionalInfo ? entity.additionalInfo.description : ''], defaultDashboardId: [entity && entity.additionalInfo ? entity.additionalInfo.defaultDashboardId : null], defaultDashboardFullscreen: [entity && entity.additionalInfo ? entity.additionalInfo.defaultDashboardFullscreen : false], + homeDashboardId: [entity && entity.additionalInfo ? entity.additionalInfo.homeDashboardId : null], + homeDashboardHideToolbar: [entity && entity.additionalInfo && + isDefinedAndNotNull(entity.additionalInfo.homeDashboardHideToolbar) ? entity.additionalInfo.homeDashboardHideToolbar : true] } ) } @@ -89,6 +92,11 @@ export class UserComponent extends EntityComponent { {defaultDashboardId: entity.additionalInfo ? entity.additionalInfo.defaultDashboardId : null}}); this.entityForm.patchValue({additionalInfo: {defaultDashboardFullscreen: entity.additionalInfo ? entity.additionalInfo.defaultDashboardFullscreen : false}}); + this.entityForm.patchValue({additionalInfo: + {homeDashboardId: entity.additionalInfo ? entity.additionalInfo.homeDashboardId : null}}); + this.entityForm.patchValue({additionalInfo: + {homeDashboardHideToolbar: entity.additionalInfo && + isDefinedAndNotNull(entity.additionalInfo.homeDashboardHideToolbar) ? entity.additionalInfo.homeDashboardHideToolbar : true}}); } } diff --git a/ui-ngx/src/app/modules/home/pages/widget/widget-library.component.html b/ui-ngx/src/app/modules/home/pages/widget/widget-library.component.html index 802bb8e65a..e48eba1ebf 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widget-library.component.html +++ b/ui-ngx/src/app/modules/home/pages/widget/widget-library.component.html @@ -35,6 +35,7 @@ [isEditActionEnabled]="true" [isExportActionEnabled]="true" [isRemoveActionEnabled]="!isReadOnly" + [disableWidgetInteraction]="true" [callbacks]="dashboardCallbacks"> diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-radios.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-radios.tsx index 876d93c6ff..c22779897e 100644 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-radios.tsx +++ b/ui-ngx/src/app/shared/components/json-form/react/json-form-radios.tsx @@ -28,12 +28,17 @@ class ThingsboardRadios extends React.Component {this.props.form.title} - { + { this.props.onChangeValidate(e); }}> {items} diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-rc-select.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-rc-select.tsx index 571f36eab7..dcfe453b61 100644 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-rc-select.tsx +++ b/ui-ngx/src/app/shared/components/json-form/react/json-form-rc-select.tsx @@ -22,6 +22,7 @@ import { KeyLabelItem } from '@shared/components/json-form/react/json-form.models'; import { Mode } from 'rc-select/lib/interface'; +import { deepClone } from '@core/utils'; interface ThingsboardRcSelectState extends JsonFormFieldState { currentValue: KeyLabelItem | KeyLabelItem[]; @@ -151,10 +152,14 @@ class ThingsboardRcSelect extends React.Component {options} diff --git a/ui-ngx/src/app/shared/models/dashboard.models.ts b/ui-ngx/src/app/shared/models/dashboard.models.ts index 1637890ce5..a92bc3d672 100644 --- a/ui-ngx/src/app/shared/models/dashboard.models.ts +++ b/ui-ngx/src/app/shared/models/dashboard.models.ts @@ -106,6 +106,15 @@ export interface Dashboard extends DashboardInfo { configuration?: DashboardConfiguration; } +export interface HomeDashboard extends Dashboard { + hideDashboardToolbar: boolean; +} + +export interface HomeDashboardInfo { + dashboardId: DashboardId; + hideDashboardToolbar: boolean; +} + export function isPublicDashboard(dashboard: DashboardInfo): boolean { if (dashboard && dashboard.assignedCustomers) { return dashboard.assignedCustomers diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index ea0e45cbd2..32c67e2fe0 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -74,6 +74,7 @@ "admin": { "general": "General", "general-settings": "General Settings", + "home-settings": "Home Settings", "outgoing-mail": "Mail Server", "outgoing-mail-settings": "Outgoing Mail Server Settings", "system-settings": "System Settings", @@ -764,7 +765,9 @@ "select-state": "Select target state", "state-controller": "State controller", "search": "Search dashboards", - "selected-dashboards": "{ count, plural, 1 {1 dashboard} other {# dashboards} } selected" + "selected-dashboards": "{ count, plural, 1 {1 dashboard} other {# dashboards} } selected", + "home-dashboard": "Home dashboard", + "home-dashboard-hide-toolbar": "Hide home dashboard toolbar" }, "datakey": { "settings": "Settings", diff --git a/ui-ngx/yarn.lock b/ui-ngx/yarn.lock index dcdc0909c0..b993a8dbd4 100644 --- a/ui-ngx/yarn.lock +++ b/ui-ngx/yarn.lock @@ -1118,6 +1118,13 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.12.5": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e" + integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/template@7.10.4", "@babel/template@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278" @@ -7941,7 +7948,7 @@ rc-util@^4.15.3: react-lifecycles-compat "^3.0.4" shallowequal "^1.1.0" -rc-util@^5.0.0, rc-util@^5.0.1, rc-util@^5.0.6, rc-util@^5.3.0: +rc-util@^5.0.0, rc-util@^5.0.1, rc-util@^5.3.0: version "5.4.0" resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.4.0.tgz#688eaeecfdae9dae2bfdf10bedbe884591dba004" integrity sha512-kXDn1JyLJTAWLBFt+fjkTcUtXhxKkipQCobQmxIEVrX62iXgo24z8YKoWehWfMxPZFPE+RXqrmEu9j5kHz/Lrg== @@ -7949,6 +7956,15 @@ rc-util@^5.0.0, rc-util@^5.0.1, rc-util@^5.0.6, rc-util@^5.3.0: react-is "^16.12.0" shallowequal "^1.1.0" +rc-util@^5.0.6: + version "5.7.0" + resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.7.0.tgz#776b14cf5bbfc24f419fd40c42ffadddda0718fc" + integrity sha512-0hh5XkJ+vBDeMJsHElqT1ijMx+gC3gpClwQ10h/5hccrrgrMx8VUem183KLlH1YrWCfMMPmDXWWNnwsn+p6URw== + dependencies: + "@babel/runtime" "^7.12.5" + react-is "^16.12.0" + shallowequal "^1.1.0" + rc-virtual-list@^1.1.2: version "1.1.6" resolved "https://registry.yarnpkg.com/rc-virtual-list/-/rc-virtual-list-1.1.6.tgz#b255baf9aacde149a8893324e6307214094f4c0a" From a07f6f5b8b2466294ab941631b4904f0e1626875 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 3 Feb 2021 15:53:51 +0200 Subject: [PATCH 110/249] created "calculate delta" rule node --- .../engine/metadata/CalculateDeltaNode.java | 175 ++++++++++++++++++ .../CalculateDeltaNodeConfiguration.java | 45 +++++ .../static/rulenode/rulenode-core-config.js | 2 +- 3 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java create mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNodeConfiguration.java diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java new file mode 100644 index 0000000000..d0bf9a70a0 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java @@ -0,0 +1,175 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.metadata; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import lombok.extern.slf4j.Slf4j; +import org.thingsboard.common.util.DonAsynchron; +import org.thingsboard.rule.engine.api.RuleNode; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNode; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.rule.engine.api.TbRelationTypes; +import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.kv.TsKvEntry; +import org.thingsboard.server.common.data.plugin.ComponentType; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.dao.timeseries.TimeseriesService; +import org.thingsboard.server.dao.util.mapping.JacksonUtil; + +import java.math.BigDecimal; +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +@Slf4j +@RuleNode(type = ComponentType.ENRICHMENT, + name = "calculate delta", + configClazz = CalculateDeltaNodeConfiguration.class, + nodeDescription = "Add delta value into message by originator Entity Id", + nodeDetails = "Calculates delta and period based on the previous data and current data. " + + "Groups incoming data based on originator id of the message (i.e. particular device, asset, customer).", + uiResources = {"static/rulenode/rulenode-core-config.js"}, + configDirective = "tbEnrichmentNodeCalculateDeltaConfig") +public class CalculateDeltaNode implements TbNode { + private Map cache; + private CalculateDeltaNodeConfiguration config; + private TbContext ctx; + private TimeseriesService timeseriesService; + private boolean useCache; + + @Override + public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { + this.config = TbNodeUtils.convert(configuration, CalculateDeltaNodeConfiguration.class); + this.ctx = ctx; + this.timeseriesService = ctx.getTimeseriesService(); + this.useCache = config.isUseCache(); + + if (useCache) { + cache = new ConcurrentHashMap<>(); + } + } + + @Override + public void onMsg(TbContext ctx, TbMsg msg) { + JsonNode json = JacksonUtil.toJsonNode(msg.getData()); + String inputKey = config.getInputValueKey(); + if (json.has(inputKey)) { + DonAsynchron.withCallback(getLastValue(msg.getOriginator()), + previousData -> { + double currentValue = json.get(inputKey).asDouble(); + long currentTs = json.has("ts") ? json.get("ts").asLong() : System.currentTimeMillis(); + + if (useCache) { + cache.put(msg.getOriginator(), new ValueWithTs(currentTs, currentValue)); + } + + BigDecimal delta = BigDecimal.valueOf(previousData != null ? currentValue - previousData.value : 0.0); + + if (config.isTellFailureIfDeltaIsNegative() && delta.doubleValue() < 0) { + ctx.tellNext(msg, TbRelationTypes.FAILURE); + return; + } + + if (config.getRound() != null) { + delta = delta.setScale(config.getRound(), BigDecimal.ROUND_HALF_UP); + } + + ObjectNode result = (ObjectNode) json; + result.put(config.getOutputValueKey(), delta); + + if (config.isAddPeriodBetweenMsgs()) { + long period = previousData != null ? currentTs - previousData.ts : 0; + result.put(config.getPeriodValueKey(), period); + } + ctx.tellSuccess(TbMsg.transformMsg(msg, msg.getType(), msg.getOriginator(), msg.getMetaData(), JacksonUtil.toString(result))); + }, + t -> ctx.tellFailure(msg, t) + , ctx.getDbCallbackExecutor()); + } else if (config.isTellFailureIfInputValueKeyIsAbsent()) { + ctx.tellNext(msg, TbRelationTypes.FAILURE); + } else { + ctx.tellSuccess(msg); + } + } + + @Override + public void destroy() { + + } + + private ListenableFuture fetchLatestValue(EntityId entityId) { + return Futures.transform(timeseriesService.findLatest(ctx.getTenantId(), entityId, Collections.singletonList(config.getInputValueKey())), + list -> extractValue(list.get(0)) + , ctx.getDbCallbackExecutor()); + } + + private ListenableFuture getLastValue(EntityId entityId) { + ValueWithTs latestValue; + if (useCache && (latestValue = cache.get(entityId)) != null) { + return Futures.immediateFuture(latestValue); + } else { + return fetchLatestValue(entityId); + } + } + + private ValueWithTs extractValue(TsKvEntry kvEntry) { + double result = 0.0; + long ts = 0; + if (kvEntry != null) { + ts = kvEntry.getTs(); + switch (kvEntry.getDataType()) { + case LONG: + result = kvEntry.getLongValue().get(); + break; + case DOUBLE: + result = kvEntry.getDoubleValue().get(); + break; + case BOOLEAN: + result = kvEntry.getBooleanValue().get() ? 1 : 0; + break; + case STRING: + String str = kvEntry.getStrValue().orElse(null); + try { + if (str == null) { + return null; + } + result = Double.parseDouble(str); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Calculation failed. Unable to parse value [" + str + "]" + + " of telemetry [" + kvEntry.getKey() + "] to Double"); + } + break; + } + } + return new ValueWithTs(ts, result); + } + + private static class ValueWithTs { + private final long ts; + private final double value; + + private ValueWithTs(long ts, double value) { + this.ts = ts; + this.value = value; + } + } +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNodeConfiguration.java new file mode 100644 index 0000000000..7978dd4172 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNodeConfiguration.java @@ -0,0 +1,45 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.metadata; + +import lombok.Data; +import org.thingsboard.rule.engine.api.NodeConfiguration; + +@Data +public class CalculateDeltaNodeConfiguration implements NodeConfiguration { + private String inputValueKey; + private String outputValueKey; + private boolean useCache; + private boolean addPeriodBetweenMsgs; + private String periodValueKey; + private Integer round; + private boolean tellFailureIfInputValueKeyIsAbsent; + private boolean tellFailureIfDeltaIsNegative; + + @Override + public CalculateDeltaNodeConfiguration defaultConfiguration() { + CalculateDeltaNodeConfiguration configuration = new CalculateDeltaNodeConfiguration(); + configuration.setInputValueKey("value"); + configuration.setOutputValueKey("valueDelta"); + configuration.setUseCache(true); + configuration.setAddPeriodBetweenMsgs(false); + configuration.setPeriodValueKey("periodInMs"); + configuration.setTellFailureIfInputValueKeyIsAbsent(true); + configuration.setTellFailureIfDeltaIsNegative(true); + return configuration; + } + +} diff --git a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js index d8f3386b04..50f08c8425 100644 --- a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js +++ b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js @@ -12,5 +12,5 @@ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - ***************************************************************************** */var g=function(e,t){return(g=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])})(e,t)};function y(e,t){function r(){this.constructor=e}g(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}function b(e,t,r,n){var a,o=arguments.length,i=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,r,n);else for(var l=e.length-1;l>=0;l--)(a=e[l])&&(i=(o<3?a(i):o>3?a(t,r,i):a(t,r))||i);return o>3&&i&&Object.defineProperty(t,r,i),i}function h(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}Object.create;function C(e){var t="function"==typeof Symbol&&Symbol.iterator,r=t&&e[t],n=0;if(r)return r.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}Object.create;var v,F=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.emptyConfigForm},r.prototype.onConfigurationSet=function(e){this.emptyConfigForm=this.fb.group({})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-node-empty-config",template:"
"}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),x=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return y(r,e),r.prototype.configForm=function(){return this.attributesConfigForm},r.prototype.onConfigurationSet=function(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]],notifyDevice:[!e||e.scope,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-attributes-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),T=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.timeseriesConfigForm},r.prototype.onConfigurationSet=function(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-timeseries-config",template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),q=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.rpcRequestConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rpc-request-config",template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),S=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.logConfigForm},r.prototype.onConfigurationSet=function(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.logConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-log-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),I=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.assignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),k=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.clearAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],alarmType:[e?e.alarmType:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-clear-alarm-config",template:'
\n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),N=function(e){function r(t,r,n,o){var i=e.call(this,t)||this;return i.store=t,i.fb=r,i.nodeScriptTestService=n,i.translate=o,i.alarmSeverities=Object.keys(a.AlarmSeverity),i.alarmSeverityTranslationMap=a.alarmSeverityTranslations,i.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],i}return y(r,e),r.prototype.configForm=function(){return this.createAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]]})},r.prototype.validatorTriggers=function(){return["useMessageAlarmData"]},r.prototype.updateValidators=function(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([i.Validators.required]),this.createAlarmConfigForm.get("severity").setValidators([i.Validators.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})},r.prototype.testScript=function(){var e=this,t=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.removeKey=function(e,t){var r=this.createAlarmConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.createAlarmConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.createAlarmConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.createAlarmConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-create-alarm-config",template:'
\n \n \n \n
\n \n
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n \n \n
\n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),V=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return y(r,e),r.prototype.configForm=function(){return this.createRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[i.Validators.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["entityType"]},r.prototype.updateValidators=function(e){var t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==a.EntityType.DEVICE&&t!==a.EntityType.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([i.Validators.required]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-create-relation-config",template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),E=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.msgDelayConfigForm},r.prototype.onConfigurationSet=function(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(1e5)]]})},r.prototype.validatorTriggers=function(){return["useMetadataPeriodInSecondsPatterns"]},r.prototype.updateValidators=function(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([i.Validators.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([i.Validators.required,i.Validators.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-msg-delay-config",template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),A=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return y(r,e),r.prototype.configForm=function(){return this.deleteRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["deleteForSingleEntity","entityType"]},r.prototype.updateValidators=function(e){var t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,r=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&r?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-delete-relation-config",template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),L=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.generatorConfigForm},r.prototype.onConfigurationSet=function(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[i.Validators.required,i.Validators.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[i.Validators.required,i.Validators.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.prepareInputConfig=function(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e},r.prototype.prepareOutputConfig=function(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e},r.prototype.testScript=function(){var e=this,t=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId).subscribe((function(t){t&&e.generatorConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-generator-config",template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent);!function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(v||(v={}));var M,P=new Map([[v.CUSTOMER,"tb.rulenode.originator-customer"],[v.TENANT,"tb.rulenode.originator-tenant"],[v.RELATED,"tb.rulenode.originator-related"],[v.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(M||(M={}));var R,w=new Map([[M.CIRCLE,"tb.rulenode.perimeter-circle"],[M.POLYGON,"tb.rulenode.perimeter-polygon"]]);!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(R||(R={}));var O,D=new Map([[R.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[R.SECONDS,"tb.rulenode.time-unit-seconds"],[R.MINUTES,"tb.rulenode.time-unit-minutes"],[R.HOURS,"tb.rulenode.time-unit-hours"],[R.DAYS,"tb.rulenode.time-unit-days"]]);!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(O||(O={}));var K,B=new Map([[O.METER,"tb.rulenode.range-unit-meter"],[O.KILOMETER,"tb.rulenode.range-unit-kilometer"],[O.FOOT,"tb.rulenode.range-unit-foot"],[O.MILE,"tb.rulenode.range-unit-mile"],[O.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(K||(K={}));var G,U,j,H=new Map([[K.TITLE,"tb.rulenode.entity-details-title"],[K.COUNTRY,"tb.rulenode.entity-details-country"],[K.STATE,"tb.rulenode.entity-details-state"],[K.ZIP,"tb.rulenode.entity-details-zip"],[K.ADDRESS,"tb.rulenode.entity-details-address"],[K.ADDRESS2,"tb.rulenode.entity-details-address2"],[K.PHONE,"tb.rulenode.entity-details-phone"],[K.EMAIL,"tb.rulenode.entity-details-email"],[K.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(G||(G={})),function(e){e.ASC="ASC",e.DESC="DESC"}(U||(U={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(j||(j={}));var z,$=new Map([[j.STANDARD,"tb.rulenode.sqs-queue-standard"],[j.FIFO,"tb.rulenode.sqs-queue-fifo"]]),Q=["anonymous","basic","cert.PEM"],_=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),W=["sas","cert.PEM"],J=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(z||(z={}));var Y=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],Z=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]),X=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=w,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=B,n.timeUnits=Object.keys(R),n.timeUnitsTranslationMap=D,n}return y(r,e),r.prototype.configForm=function(){return this.geoActionConfigForm},r.prototype.onConfigurationSet=function(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[i.Validators.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterType").setValidators([]):this.geoActionConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoActionConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoActionConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.msgCountConfigForm},r.prototype.onConfigurationSet=function(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[i.Validators.required,i.Validators.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-msg-count-config",template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.rpcReplyConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rpc-reply-config",template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.saveToCustomTableConfigForm},r.prototype.onConfigurationSet=function(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[i.Validators.required]],fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-custom-table-config",template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n \n \n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ne=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.translate=r,o.injector=n,o.fb=a,o.propagateChange=null,o.valueChangeSubscription=null,o}var a;return y(r,e),a=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){this.ngControl=this.injector.get(i.NgControl),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))},r.prototype.keyValsFormArray=function(){return this.kvListFormGroup.get("keyVals")},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t,r,n=this;this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();var a=[];if(e)try{for(var o=C(Object.keys(e)),l=o.next();!l.done;l=o.next()){var s=l.value;Object.prototype.hasOwnProperty.call(e,s)&&a.push(this.fb.group({key:[s,[i.Validators.required]],value:[e[s],[i.Validators.required]]}))}}catch(e){t={error:e}}finally{try{l&&!l.done&&(r=o.return)&&r.call(o)}finally{if(t)throw t.error}}this.kvListFormGroup.setControl("keyVals",this.fb.array(a)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((function(){n.updateModel()}))},r.prototype.removeKeyVal=function(e){this.kvListFormGroup.get("keyVals").removeAt(e)},r.prototype.addKeyVal=function(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[i.Validators.required]],value:["",[i.Validators.required]]}))},r.prototype.validate=function(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}},r.prototype.updateModel=function(){var e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{var t={};e.forEach((function(e){t[e.key]=e.value})),this.propagateChange(t)}},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:t.Injector},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",String)],r.prototype,"requiredText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"keyText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"keyRequiredText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"valText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"valRequiredText",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=a=b([t.Component({selector:"tb-kv-map-config",template:'
\n
\n {{ keyText }}\n {{ valText }}\n \n
\n
\n
\n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n \n
\n \n
\n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return a})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return a})),multi:!0}],styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:rgba(0,0,0,.54);font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}"]}),h("design:paramtypes",[o.Store,n.TranslateService,t.Injector,i.FormBuilder])],r)}(a.PageComponent),ae=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n.propagateChange=null,n}var n;return y(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[i.Validators.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((function(t){e.deviceRelationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=b([t.Component({selector:"tb-device-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-type
\n \n \n
device.device-types
\n \n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.propagateChange=null,n}var n;return y(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((function(t){e.relationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=b([t.Component({selector:"tb-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),ie=function(e){function r(t,r,n,o){var i,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.truncate=n,s.fb=o,s.placeholder="tb.rulenode.message-type",s.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],s.messageTypes=[],s.messageTypesList=[],s.searchText="",s.propagateChange=function(e){},s.messageTypeConfigForm=s.fb.group({messageType:[null]});try{for(var u=C(Object.keys(a.MessageType)),d=u.next();!d.done;d=u.next()){var p=d.value;s.messageTypesList.push({name:a.messageTypeNames.get(a.MessageType[p]),value:p})}}catch(e){i={error:e}}finally{try{d&&!d.done&&(l=u.return)&&l.call(u)}finally{if(i)throw i.error}}return s}var l;return y(r,e),l=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.ngOnInit=function(){var e=this;this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(t){return e.fetchMessageTypes(t)})),f.share())},r.prototype.ngAfterViewInit=function(){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t=this;this.searchText="",this.messageTypes.length=0,e&&e.forEach((function(e){var r=t.messageTypesList.find((function(t){return t.value===e}));r?t.messageTypes.push({name:r.name,value:r.value}):t.messageTypes.push({name:e,value:e})}))},r.prototype.displayMessageTypeFn=function(e){return e?e.name:void 0},r.prototype.textIsNotEmpty=function(e){return!!(e&&null!=e&&e.length>0)},r.prototype.createMessageType=function(e,t){e.preventDefault(),this.transformMessageType(t)},r.prototype.add=function(e){this.transformMessageType(e.value)},r.prototype.fetchMessageTypes=function(e){if(this.searchText=e,this.searchText&&this.searchText.length){var t=this.searchText.toUpperCase();return c.of(this.messageTypesList.filter((function(e){return e.name.toUpperCase().includes(t)})))}return c.of(this.messageTypesList)},r.prototype.transformMessageType=function(e){if((e||"").trim()){var t=null,r=e.trim(),n=this.messageTypesList.find((function(e){return e.name===r}));(t=n?{name:n.name,value:n.value}:{name:r,value:r})&&this.addMessageType(t)}this.clear("")},r.prototype.remove=function(e){var t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())},r.prototype.selected=function(e){this.addMessageType(e.option.value),this.clear("")},r.prototype.addMessageType=function(e){-1===this.messageTypes.findIndex((function(t){return t.value===e.value}))&&(this.messageTypes.push(e),this.updateModel())},r.prototype.onFocus=function(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((function(){t.messageTypeInput.nativeElement.blur(),t.messageTypeInput.nativeElement.focus()}),0)},r.prototype.updateModel=function(){var e=this.messageTypes.map((function(e){return e.value}));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:a.TruncatePipe},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),b([t.Input(),h("design:type",String)],r.prototype,"label",void 0),b([t.Input(),h("design:type",Object)],r.prototype,"placeholder",void 0),b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.ViewChild("chipList",{static:!1}),h("design:type",d.MatChipList)],r.prototype,"chipList",void 0),b([t.ViewChild("messageTypeAutocomplete",{static:!1}),h("design:type",p.MatAutocomplete)],r.prototype,"matAutocomplete",void 0),b([t.ViewChild("messageTypeInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"messageTypeInput",void 0),r=l=b([t.Component({selector:"tb-message-types-config",template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return l})),multi:!0}]}),h("design:paramtypes",[o.Store,n.TranslateService,a.TruncatePipe,i.FormBuilder])],r)}(a.PageComponent),le=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.subscriptions=[],n.disableCertPemCredentials=!1,n.allCredentialsTypes=Q,n.credentialsTypeTranslationsMap=_,n.propagateChange=null,n}var n;return y(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.credentialsConfigFormGroup=this.fb.group({type:[null,[i.Validators.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(f.distinctUntilChanged()).subscribe((function(){e.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((function(){e.credentialsTypeChanged()})))},r.prototype.ngOnChanges=function(e){var t,r,n=this;try{for(var a=C(Object.keys(e)),o=a.next();!o.done;o=a.next()){var i=o.value,l=e[i];if(!l.firstChange&&l.currentValue!==l.previousValue)if(l.currentValue&&"disableCertPemCredentials"===i)"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((function(){n.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}catch(e){t={error:e}}finally{try{o&&!o.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}},r.prototype.ngOnDestroy=function(){this.subscriptions.forEach((function(e){return e.unsubscribe()}))},r.prototype.writeValue=function(e){s.isDefinedAndNotNull(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))},r.prototype.setDisabledState=function(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())},r.prototype.updateView=function(){var e=this.credentialsConfigFormGroup.value,t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.validate=function(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}},r.prototype.credentialsTypeChanged=function(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()},r.prototype.updateValidators=function(e){void 0===e&&(e=!1);var t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([i.Validators.required]),this.credentialsConfigFormGroup.get("password").setValidators([i.Validators.required]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(i.Validators.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})},r.prototype.requiredFilesSelected=function(e,t){return void 0===t&&(t=null),function(r){return t||(t=[Object.keys(r.controls)]),(null==r?void 0:r.controls)&&t.some((function(t){return t.every((function(t){return!e(r.controls[t])}))}))?null:{notAllRequiredFilesSelected:!0}}},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),b([t.Input(),h("design:type",Object)],r.prototype,"disableCertPemCredentials",void 0),r=n=b([t.Component({selector:"tb-credentials-config",template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n
\n
\n
\n
\n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),se=function(){function e(){}return e=b([t.NgModule({declarations:[ne,ae,oe,ie,le],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule],exports:[ne,ae,oe,ie,le]})],e)}(),me=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.unassignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-un-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ue=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.snsConfigForm},r.prototype.onConfigurationSet=function(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[i.Validators.required]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-sns-config",template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),de=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.sqsQueueType=j,n.sqsQueueTypes=Object.keys(j),n.sqsQueueTypeTranslationsMap=$,n}return y(r,e),r.prototype.configForm=function(){return this.sqsConfigForm},r.prototype.onConfigurationSet=function(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[i.Validators.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[i.Validators.required]],delaySeconds:[e?e.delaySeconds:null,[i.Validators.min(0),i.Validators.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-sqs-config",template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.pubSubConfigForm},r.prototype.onConfigurationSet=function(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[i.Validators.required]],topicName:[e?e.topicName:null,[i.Validators.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[i.Validators.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[i.Validators.required]],messageAttributes:[e?e.messageAttributes:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-pub-sub-config",template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.ackValues=["all","-1","0","1"],n.ToByteStandartCharsetTypesValues=Y,n.ToByteStandartCharsetTypeTranslationMap=Z,n}return y(r,e),r.prototype.configForm=function(){return this.kafkaConfigForm},r.prototype.onConfigurationSet=function(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],bootstrapServers:[e?e.bootstrapServers:null,[i.Validators.required]],retries:[e?e.retries:null,[i.Validators.min(0)]],batchSize:[e?e.batchSize:null,[i.Validators.min(0)]],linger:[e?e.linger:null,[i.Validators.min(0)]],bufferMemory:[e?e.bufferMemory:null,[i.Validators.min(0)]],acks:[e?e.acks:null,[i.Validators.required]],keySerializer:[e?e.keySerializer:null,[i.Validators.required]],valueSerializer:[e?e.valueSerializer:null,[i.Validators.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})},r.prototype.validatorTriggers=function(){return["addMetadataKeyValuesAsKafkaHeaders"]},r.prototype.updateValidators=function(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([i.Validators.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-kafka-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.mqttConfigForm},r.prototype.onConfigurationSet=function(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-mqtt-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n \n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],n}return y(r,e),r.prototype.configForm=function(){return this.rabbitMqConfigForm},r.prototype.onConfigurationSet=function(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[i.Validators.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[i.Validators.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rabbit-mq-config",template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ye=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.proxySchemes=["http","https"],n.httpRequestTypes=Object.keys(z),n}return y(r,e),r.prototype.configForm=function(){return this.restApiCallConfigForm},r.prototype.onConfigurationSet=function(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[i.Validators.required]],requestMethod:[e?e.requestMethod:null,[i.Validators.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[i.Validators.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})},r.prototype.validatorTriggers=function(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]},r.prototype.updateValidators=function(e){var t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,r=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,n=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;n&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(n?[i.Validators.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(n?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([i.Validators.min(0)])),r?this.restApiCallConfigForm.get("maxQueueSize").setValidators([i.Validators.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rest-api-call-config",template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n \n \n \n tb.rulenode.max-parallel-requests-count\n \n \n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.smtpProtocols=["smtp","smtps"],n.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"],n}return y(r,e),r.prototype.configForm=function(){return this.sendEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmtpSettings","enableProxy"]},r.prototype.updateValidators=function(e){var t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,r=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([i.Validators.required,i.Validators.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(r?[i.Validators.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(r?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-send-email-config",template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),he=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.serviceType=a.ServiceType.TB_RULE_ENGINE,n}return y(r,e),r.prototype.configForm=function(){return this.checkPointConfigForm},r.prototype.onConfigurationSet=function(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-check-point-config",template:'
\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allAzureIotHubCredentialsTypes=W,n.azureIotHubCredentialsTypeTranslationsMap=J,n}return y(r,e),r.prototype.configForm=function(){return this.azureIotHubConfigForm},r.prototype.onConfigurationSet=function(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[i.Validators.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[i.Validators.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})},r.prototype.prepareOutputConfig=function(e){var t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e},r.prototype.validatorTriggers=function(){return["credentials.type"]},r.prototype.updateValidators=function(e){var t=this.azureIotHubConfigForm.get("credentials"),r=t.get("type").value;switch(e&&t.reset({type:r},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),r){case"sas":t.get("sasKey").setValidators([i.Validators.required]);break;case"cert.PEM":t.get("privateKey").setValidators([i.Validators.required]),t.get("privateKeyFileName").setValidators([i.Validators.required]),t.get("cert").setValidators([i.Validators.required]),t.get("certFileName").setValidators([i.Validators.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-azure-iot-hub-config",template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.deviceProfile},r.prototype.onConfigurationSet=function(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,i.Validators.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,i.Validators.required]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-device-profile-config",template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.sendSmsConfigForm},r.prototype.onConfigurationSet=function(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[i.Validators.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[i.Validators.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmsSettings"]},r.prototype.updateValidators=function(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([i.Validators.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-send-sms-config",template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),xe=function(){function e(){}return e=b([t.NgModule({declarations:[x,T,q,S,I,k,N,V,E,A,L,X,ee,te,re,me,ue,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule,se],exports:[x,T,q,S,I,k,N,V,E,A,L,X,ee,te,re,me,ue,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe]})],e)}(),Te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.checkMessageConfigForm},r.prototype.onConfigurationSet=function(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})},r.prototype.validateConfig=function(){var e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0},r.prototype.removeMessageName=function(e){var t=this.checkMessageConfigForm.get("messageNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))},r.prototype.removeMetadataName=function(e){var t=this.checkMessageConfigForm.get("metadataNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))},r.prototype.addMessageName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("messageNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("messageNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.prototype.addMetadataName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("metadataNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("metadataNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-check-message-config",template:'
\n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),qe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.entitySearchDirection=Object.keys(a.EntitySearchDirection),n.entitySearchDirectionTranslationsMap=a.entitySearchDirectionTranslations,n}return y(r,e),r.prototype.configForm=function(){return this.checkRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],relationType:[e?e.relationType:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["checkForSingleEntity"]},r.prototype.updateValidators=function(e){var t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-check-relation-config",template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=w,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=B,n}return y(r,e),r.prototype.configForm=function(){return this.geoFilterConfigForm},r.prototype.onConfigurationSet=function(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterType").setValidators([]):this.geoFilterConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoFilterConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoFilterConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ie=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.messageTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-message-type-config",template:'
\n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allowedEntityTypes=[a.EntityType.DEVICE,a.EntityType.ASSET,a.EntityType.ENTITY_VIEW,a.EntityType.TENANT,a.EntityType.CUSTOMER,a.EntityType.USER,a.EntityType.DASHBOARD,a.EntityType.RULE_CHAIN,a.EntityType.RULE_NODE],n}return y(r,e),r.prototype.configForm=function(){return this.originatorTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-originator-type-config",template:'
\n \n \n \n
\n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ne=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-filter-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Ve=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.switchConfigForm},r.prototype.onConfigurationSet=function(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.switchConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-filter-node-switch-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Ee=function(e){function r(t,r,n){var o,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.fb=n,s.alarmStatusTranslationsMap=a.alarmStatusTranslations,s.alarmStatusList=[],s.searchText="",s.displayStatusFn=s.displayStatus.bind(s);try{for(var m=C(Object.keys(a.AlarmStatus)),u=m.next();!u.done;u=m.next()){var d=u.value;s.alarmStatusList.push(a.AlarmStatus[d])}}catch(e){o={error:e}}finally{try{u&&!u.done&&(l=m.return)&&l.call(m)}finally{if(o)throw o.error}}return s.statusFormControl=new i.FormControl(""),s.filteredAlarmStatus=s.statusFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return s.fetchAlarmStatus(e)})),f.share()),s}return y(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.alarmStatusConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[i.Validators.required]]})},r.prototype.displayStatus=function(e){return e?this.translate.instant(a.alarmStatusTranslations.get(e)):void 0},r.prototype.fetchAlarmStatus=function(e){var t=this,r=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){var n=this.searchText.toUpperCase();return c.of(r.filter((function(e){return t.translate.instant(a.alarmStatusTranslations.get(a.AlarmStatus[e])).toUpperCase().includes(n)})))}return c.of(r)},r.prototype.alarmStatusSelected=function(e){this.addAlarmStatus(e.option.value),this.clear("")},r.prototype.removeAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}},r.prototype.addAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))},r.prototype.getAlarmStatusList=function(){var e=this;return this.alarmStatusList.filter((function(t){return-1===e.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(t)}))},r.prototype.onAlarmStatusInputFocus=function(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.alarmStatusInput.nativeElement.blur(),t.alarmStatusInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},b([t.ViewChild("alarmStatusInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"alarmStatusInput",void 0),r=b([t.Component({selector:"tb-filter-node-check-alarm-status-config",template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n'}),h("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ae=function(){function e(){}return e=b([t.NgModule({declarations:[Te,qe,Se,Ie,ke,Ne,Ve,Ee],imports:[r.CommonModule,a.SharedModule,se],exports:[Te,qe,Se,Ie,ke,Ne,Ve,Ee]})],e)}(),Le=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.customerAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-customer-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Me=function(e){function r(t,r,n){var a,o,l=e.call(this,t)||this;l.store=t,l.translate=r,l.fb=n,l.entityDetailsTranslationsMap=H,l.entityDetailsList=[],l.searchText="",l.displayDetailsFn=l.displayDetails.bind(l);try{for(var s=C(Object.keys(K)),m=s.next();!m.done;m=s.next()){var u=m.value;l.entityDetailsList.push(K[u])}}catch(e){a={error:e}}finally{try{m&&!m.done&&(o=s.return)&&o.call(s)}finally{if(a)throw a.error}}return l.detailsFormControl=new i.FormControl(""),l.filteredEntityDetails=l.detailsFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return l.fetchEntityDetails(e)})),f.share()),l}return y(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.entityDetailsConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[i.Validators.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})},r.prototype.displayDetails=function(e){return e?this.translate.instant(H.get(e)):void 0},r.prototype.fetchEntityDetails=function(e){var t=this;if(this.searchText=e,this.searchText&&this.searchText.length){var r=this.searchText.toUpperCase();return c.of(this.entityDetailsList.filter((function(e){return t.translate.instant(H.get(K[e])).toUpperCase().includes(r)})))}return c.of(this.entityDetailsList)},r.prototype.detailsFieldSelected=function(e){this.addDetailsField(e.option.value),this.clear("")},r.prototype.removeDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}},r.prototype.addDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))},r.prototype.onEntityDetailsInputFocus=function(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.detailsInput.nativeElement.blur(),t.detailsInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},b([t.ViewChild("detailsInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"detailsInput",void 0),r=b([t.Component({selector:"tb-enrichment-node-entity-details-config",template:'
\n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-entity-details-matching\n
\n
\n
\n
\n
\n \n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
tb.rulenode.add-to-metadata-hint
\n
\n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}"]}),h("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.deviceAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[i.Validators.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.deviceAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.deviceAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.deviceAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.deviceAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-device-attributes-config",template:'
\n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.originatorAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.originatorAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.originatorAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.originatorAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.originatorAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-originator-attributes-config",template:'
\n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),we=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.originatorFieldsConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-originator-fields-config",template:'
\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n.fetchMode=G,n.fetchModes=Object.keys(G),n.samplingOrders=Object.keys(U),n.timeUnits=Object.keys(R),n.timeUnitsTranslationMap=D,n}return y(r,e),r.prototype.configForm=function(){return this.getTelemetryFromDatabaseConfigForm},r.prototype.onConfigurationSet=function(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],fetchMode:[e?e.fetchMode:null,[i.Validators.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchMode","useMetadataIntervalPatterns"]},r.prototype.updateValidators=function(e){var t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,r=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===G.ALL?(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([i.Validators.required,i.Validators.min(2),i.Validators.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),r?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([i.Validators.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})},r.prototype.removeKey=function(e,t){var r=this.getTelemetryFromDatabaseConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.getTelemetryFromDatabaseConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-get-telemetry-from-database",template:'
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
\n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
\n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-interval-patterns-hint
\n
\n
\n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),De=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.relatedAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[i.Validators.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-related-attributes-config",template:'
\n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.tenantAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-tenant-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Be=function(){function e(){}return e=b([t.NgModule({declarations:[Le,Me,Pe,Re,we,Oe,De,Ke],imports:[r.CommonModule,a.SharedModule,se],exports:[Le,Me,Pe,Re,we,Oe,De,Ke]})],e)}(),Ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.originatorSource=v,n.originatorSources=Object.keys(v),n.originatorSourceTranslationMap=P,n}return y(r,e),r.prototype.configForm=function(){return this.changeOriginatorConfigForm},r.prototype.onConfigurationSet=function(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[i.Validators.required]],relationsQuery:[e?e.relationsQuery:null,[]]})},r.prototype.validatorTriggers=function(){return["originatorSource"]},r.prototype.updateValidators=function(e){var t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===v.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([i.Validators.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-transformation-node-change-originator-config",template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ue=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-transformation-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),je=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.toEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[i.Validators.required]],toTemplate:[e?e.toTemplate:null,[i.Validators.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[i.Validators.required]],bodyTemplate:[e?e.bodyTemplate:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-transformation-node-to-email-config",template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),He=function(){function e(){}return e=b([t.NgModule({declarations:[Ge,Ue,je],imports:[r.CommonModule,a.SharedModule,se],exports:[Ge,Ue,je]})],e)}(),ze=function(){function e(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-name-pattern-hint":"Name pattern, use ${metaKeyName} to substitute variables from metadata","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-type-pattern-hint":"Type pattern, use ${metaKeyName} to substitute variables from metadata","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-name-pattern-hint":"Customer name pattern, use ${metaKeyName} to substitute variables from metadata","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","client-attributes-hint":"Client attributes, use ${metaKeyName} to substitute variables from metadata","shared-attributes":"Shared attributes","shared-attributes-hint":"Shared attributes, use ${metaKeyName} to substitute variables from metadata","server-attributes":"Server attributes","server-attributes-hint":"Server attributes, use ${metaKeyName} to substitute variables from metadata","notify-device":"Notify Device","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","latest-timeseries":"Latest timeseries","latest-timeseries-hint":"Latest timeseries, use ${metaKeyName} to substitute variables from metadata","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-hint":"Relation type pattern, use ${metaKeyName} to substitute variables from metadata","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use metadata period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds metadata pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","period-in-seconds-pattern-hint":"Period in seconds pattern, use ${metaKeyName} to substitute variables from metadata","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","from-template-hint":"From address template, use ${metaKeyName} to substitute variables from metadata","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":"Comma separated address list, use ${metaKeyName} to substitute variables from metadata","cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","subject-template-hint":"Mail subject template, use ${metaKeyName} to substitute variables from metadata","body-template":"Body Template","body-template-required":"Body Template is required","body-template-hint":"Mail body template, use ${metaKeyName} to substitute variables from metadata","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","endpoint-url-pattern-hint":"HTTP URL address pattern, use ${metaKeyName} to substitute variables from metadata","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":"Use ${metaKeyName} in header/value fields to substitute variables from metadata",header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required","mqtt-topic-pattern-hint":"MQTT topic pattern, use ${metaKeyName} to substitute variables from metadata",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","topic-arn-pattern-hint":"Topic ARN pattern, use ${metaKeyName} to substitute variables from metadata","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","queue-url-pattern-hint":"Queue URL pattern, use ${metaKeyName} to substitute variables from metadata","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":"Use ${metaKeyName} in name/value fields to substitute variables from metadata","connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file *","private-key":"Client private key file *",cert:"Client certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use metadata interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","start-interval-pattern-hint":"Start interval pattern, use ${metaKeyName} to substitute variables from metadata","end-interval-pattern-hint":"End interval pattern, use ${metaKeyName} to substitute variables from metadata","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":"Comma separated Phone Numbers, use ${metaKeyName} to substitute variables from metadata","sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","sms-message-template-hint":"SMS message template, use ${metaKeyName} to substitute variables from metadata","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-zip":"Zip","entity-details-address":"Address","entity-details-address2":"Address2","entity-details-additional_info":"Additional Info","entity-details-phone":"Phone","entity-details-email":"Email","add-to-metadata":"Add selected details to message metadata","add-to-metadata-hint":"If selected, adds the selected details keys to the message metadata instead of message data.","entity-details-list-empty":"No entity details selected.","no-entity-details-matching":"No entity details matching were found.","custom-table-name":"Custom table name","custom-table-name-required":"Table Name is required","custom-table-hint":"You should enter the table name without prefix 'cs_tb_'.","message-field":"Message field","message-field-required":"Message field is required.","table-col":"Table column","table-col-required":"Table column is required.","latitude-key-name":"Latitude key name","longitude-key-name":"Longitude key name","latitude-key-name-required":"Latitude key name is required.","longitude-key-name-required":"Longitude key name is required.","fetch-perimeter-info-from-message-metadata":"Fetch perimeter information from message metadata","perimeter-circle":"Circle","perimeter-polygon":"Polygon","perimeter-type":"Perimeter type","circle-center-latitude":"Center latitude","circle-center-latitude-required":"Center latitude is required.","circle-center-longitude":"Center longitude","circle-center-longitude-required":"Center longitude is required.","range-unit-meter":"Meter","range-unit-kilometer":"Kilometer","range-unit-foot":"Foot","range-unit-mile":"Mile","range-unit-nautical-mile":"Nautical mile","range-units":"Range units",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].","min-inside-duration":"Minimal inside duration","min-inside-duration-value-required":"Minimal inside duration is required","min-inside-duration-time-unit":"Minimal inside duration time unit","min-outside-duration":"Minimal outside duration","min-outside-duration-value-required":"Minimal outside duration is required","min-outside-duration-time-unit":"Minimal outside duration time unit","tell-failure-if-absent":"Tell Failure","tell-failure-if-absent-hint":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"get-latest-value-with-ts":"Fetch Latest telemetry with Timestamp","get-latest-value-with-ts-hint":'If selected, latest telemetry values will be added to the outbound message metadata with timestamp, e.g: "temp": "{\\"ts\\":1574329385897,\\"value\\":42}"',"use-redis-queue":"Use redis queue for message persistence","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules"},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"}}},!0)}(e)}return e.ctorParameters=function(){return[{type:n.TranslateService}]},e=b([t.NgModule({declarations:[F],imports:[r.CommonModule,a.SharedModule],exports:[xe,Ae,Be,He,F]}),h("design:paramtypes",[n.TranslateService])],e)}();e.RuleNodeCoreConfigModule=ze,e.ɵa=F,e.ɵb=xe,e.ɵba=he,e.ɵbb=Ce,e.ɵbc=ve,e.ɵbd=Fe,e.ɵbe=se,e.ɵbf=ne,e.ɵbg=ae,e.ɵbh=oe,e.ɵbi=ie,e.ɵbj=le,e.ɵbk=Ae,e.ɵbl=Te,e.ɵbm=qe,e.ɵbn=Se,e.ɵbo=Ie,e.ɵbp=ke,e.ɵbq=Ne,e.ɵbr=Ve,e.ɵbs=Ee,e.ɵbt=Be,e.ɵbu=Le,e.ɵbv=Me,e.ɵbw=Pe,e.ɵbx=Re,e.ɵby=we,e.ɵbz=Oe,e.ɵc=x,e.ɵca=De,e.ɵcb=Ke,e.ɵcc=He,e.ɵcd=Ge,e.ɵce=Ue,e.ɵcf=je,e.ɵd=T,e.ɵe=q,e.ɵf=S,e.ɵg=I,e.ɵh=k,e.ɵi=N,e.ɵj=V,e.ɵk=E,e.ɵl=A,e.ɵm=L,e.ɵn=X,e.ɵo=ee,e.ɵp=te,e.ɵq=re,e.ɵr=me,e.ɵs=ue,e.ɵt=de,e.ɵu=pe,e.ɵv=ce,e.ɵw=fe,e.ɵx=ge,e.ɵy=ye,e.ɵz=be,Object.defineProperty(e,"__esModule",{value:!0})})); + ***************************************************************************** */var g=function(e,t){return(g=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])})(e,t)};function y(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}g(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}function b(e,t,r,n){var a,o=arguments.length,i=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,r,n);else for(var l=e.length-1;l>=0;l--)(a=e[l])&&(i=(o<3?a(i):o>3?a(t,r,i):a(t,r))||i);return o>3&&i&&Object.defineProperty(t,r,i),i}function h(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}Object.create;function C(e){var t="function"==typeof Symbol&&Symbol.iterator,r=t&&e[t],n=0;if(r)return r.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}Object.create;var v,F=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.emptyConfigForm},r.prototype.onConfigurationSet=function(e){this.emptyConfigForm=this.fb.group({})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-node-empty-config",template:"
"}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),x=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return y(r,e),r.prototype.configForm=function(){return this.attributesConfigForm},r.prototype.onConfigurationSet=function(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]],notifyDevice:[!e||e.scope,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-attributes-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),T=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.timeseriesConfigForm},r.prototype.onConfigurationSet=function(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-timeseries-config",template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),q=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.rpcRequestConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rpc-request-config",template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),S=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.logConfigForm},r.prototype.onConfigurationSet=function(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.logConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-log-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),I=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.assignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),k=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.clearAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],alarmType:[e?e.alarmType:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-clear-alarm-config",template:'
\n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),N=function(e){function r(t,r,n,o){var i=e.call(this,t)||this;return i.store=t,i.fb=r,i.nodeScriptTestService=n,i.translate=o,i.alarmSeverities=Object.keys(a.AlarmSeverity),i.alarmSeverityTranslationMap=a.alarmSeverityTranslations,i.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],i}return y(r,e),r.prototype.configForm=function(){return this.createAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]]})},r.prototype.validatorTriggers=function(){return["useMessageAlarmData"]},r.prototype.updateValidators=function(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([i.Validators.required]),this.createAlarmConfigForm.get("severity").setValidators([i.Validators.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})},r.prototype.testScript=function(){var e=this,t=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.removeKey=function(e,t){var r=this.createAlarmConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.createAlarmConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.createAlarmConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.createAlarmConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-create-alarm-config",template:'
\n \n \n \n
\n \n
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n \n \n
\n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),V=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return y(r,e),r.prototype.configForm=function(){return this.createRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[i.Validators.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["entityType"]},r.prototype.updateValidators=function(e){var t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==a.EntityType.DEVICE&&t!==a.EntityType.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([i.Validators.required]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-create-relation-config",template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),E=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.msgDelayConfigForm},r.prototype.onConfigurationSet=function(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(1e5)]]})},r.prototype.validatorTriggers=function(){return["useMetadataPeriodInSecondsPatterns"]},r.prototype.updateValidators=function(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([i.Validators.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([i.Validators.required,i.Validators.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-msg-delay-config",template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),A=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return y(r,e),r.prototype.configForm=function(){return this.deleteRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["deleteForSingleEntity","entityType"]},r.prototype.updateValidators=function(e){var t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,r=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&r?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-delete-relation-config",template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),L=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.generatorConfigForm},r.prototype.onConfigurationSet=function(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[i.Validators.required,i.Validators.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[i.Validators.required,i.Validators.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.prepareInputConfig=function(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e},r.prototype.prepareOutputConfig=function(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e},r.prototype.testScript=function(){var e=this,t=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId).subscribe((function(t){t&&e.generatorConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-generator-config",template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent);!function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(v||(v={}));var M,P=new Map([[v.CUSTOMER,"tb.rulenode.originator-customer"],[v.TENANT,"tb.rulenode.originator-tenant"],[v.RELATED,"tb.rulenode.originator-related"],[v.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(M||(M={}));var w,R=new Map([[M.CIRCLE,"tb.rulenode.perimeter-circle"],[M.POLYGON,"tb.rulenode.perimeter-polygon"]]);!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(w||(w={}));var D,O=new Map([[w.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[w.SECONDS,"tb.rulenode.time-unit-seconds"],[w.MINUTES,"tb.rulenode.time-unit-minutes"],[w.HOURS,"tb.rulenode.time-unit-hours"],[w.DAYS,"tb.rulenode.time-unit-days"]]);!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(D||(D={}));var K,B=new Map([[D.METER,"tb.rulenode.range-unit-meter"],[D.KILOMETER,"tb.rulenode.range-unit-kilometer"],[D.FOOT,"tb.rulenode.range-unit-foot"],[D.MILE,"tb.rulenode.range-unit-mile"],[D.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(K||(K={}));var G,U,j,H=new Map([[K.TITLE,"tb.rulenode.entity-details-title"],[K.COUNTRY,"tb.rulenode.entity-details-country"],[K.STATE,"tb.rulenode.entity-details-state"],[K.ZIP,"tb.rulenode.entity-details-zip"],[K.ADDRESS,"tb.rulenode.entity-details-address"],[K.ADDRESS2,"tb.rulenode.entity-details-address2"],[K.PHONE,"tb.rulenode.entity-details-phone"],[K.EMAIL,"tb.rulenode.entity-details-email"],[K.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(G||(G={})),function(e){e.ASC="ASC",e.DESC="DESC"}(U||(U={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(j||(j={}));var z,$=new Map([[j.STANDARD,"tb.rulenode.sqs-queue-standard"],[j.FIFO,"tb.rulenode.sqs-queue-fifo"]]),Q=["anonymous","basic","cert.PEM"],_=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),W=["sas","cert.PEM"],J=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(z||(z={}));var Y=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],Z=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]),X=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=R,n.rangeUnits=Object.keys(D),n.rangeUnitTranslationMap=B,n.timeUnits=Object.keys(w),n.timeUnitsTranslationMap=O,n}return y(r,e),r.prototype.configForm=function(){return this.geoActionConfigForm},r.prototype.onConfigurationSet=function(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[i.Validators.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterType").setValidators([]):this.geoActionConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoActionConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoActionConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.msgCountConfigForm},r.prototype.onConfigurationSet=function(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[i.Validators.required,i.Validators.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-msg-count-config",template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.rpcReplyConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rpc-reply-config",template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.saveToCustomTableConfigForm},r.prototype.onConfigurationSet=function(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[i.Validators.required]],fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-custom-table-config",template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n \n \n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ne=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.translate=r,o.injector=n,o.fb=a,o.propagateChange=null,o.valueChangeSubscription=null,o}var a;return y(r,e),a=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){this.ngControl=this.injector.get(i.NgControl),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))},r.prototype.keyValsFormArray=function(){return this.kvListFormGroup.get("keyVals")},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t,r,n=this;this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();var a=[];if(e)try{for(var o=C(Object.keys(e)),l=o.next();!l.done;l=o.next()){var s=l.value;Object.prototype.hasOwnProperty.call(e,s)&&a.push(this.fb.group({key:[s,[i.Validators.required]],value:[e[s],[i.Validators.required]]}))}}catch(e){t={error:e}}finally{try{l&&!l.done&&(r=o.return)&&r.call(o)}finally{if(t)throw t.error}}this.kvListFormGroup.setControl("keyVals",this.fb.array(a)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((function(){n.updateModel()}))},r.prototype.removeKeyVal=function(e){this.kvListFormGroup.get("keyVals").removeAt(e)},r.prototype.addKeyVal=function(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[i.Validators.required]],value:["",[i.Validators.required]]}))},r.prototype.validate=function(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}},r.prototype.updateModel=function(){var e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{var t={};e.forEach((function(e){t[e.key]=e.value})),this.propagateChange(t)}},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:t.Injector},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",String)],r.prototype,"requiredText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"keyText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"keyRequiredText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"valText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"valRequiredText",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=a=b([t.Component({selector:"tb-kv-map-config",template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n \n
\n \n
\n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return a})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return a})),multi:!0}],styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:rgba(0,0,0,.54);font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}"]}),h("design:paramtypes",[o.Store,n.TranslateService,t.Injector,i.FormBuilder])],r)}(a.PageComponent),ae=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n.propagateChange=null,n}var n;return y(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[i.Validators.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((function(t){e.deviceRelationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=b([t.Component({selector:"tb-device-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-type
\n \n \n
device.device-types
\n \n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.propagateChange=null,n}var n;return y(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((function(t){e.relationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=b([t.Component({selector:"tb-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),ie=function(e){function r(t,r,n,o){var i,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.truncate=n,s.fb=o,s.placeholder="tb.rulenode.message-type",s.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],s.messageTypes=[],s.messageTypesList=[],s.searchText="",s.propagateChange=function(e){},s.messageTypeConfigForm=s.fb.group({messageType:[null]});try{for(var u=C(Object.keys(a.MessageType)),d=u.next();!d.done;d=u.next()){var p=d.value;s.messageTypesList.push({name:a.messageTypeNames.get(a.MessageType[p]),value:p})}}catch(e){i={error:e}}finally{try{d&&!d.done&&(l=u.return)&&l.call(u)}finally{if(i)throw i.error}}return s}var l;return y(r,e),l=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.ngOnInit=function(){var e=this;this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(t){return e.fetchMessageTypes(t)})),f.share())},r.prototype.ngAfterViewInit=function(){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t=this;this.searchText="",this.messageTypes.length=0,e&&e.forEach((function(e){var r=t.messageTypesList.find((function(t){return t.value===e}));r?t.messageTypes.push({name:r.name,value:r.value}):t.messageTypes.push({name:e,value:e})}))},r.prototype.displayMessageTypeFn=function(e){return e?e.name:void 0},r.prototype.textIsNotEmpty=function(e){return!!(e&&null!=e&&e.length>0)},r.prototype.createMessageType=function(e,t){e.preventDefault(),this.transformMessageType(t)},r.prototype.add=function(e){this.transformMessageType(e.value)},r.prototype.fetchMessageTypes=function(e){if(this.searchText=e,this.searchText&&this.searchText.length){var t=this.searchText.toUpperCase();return c.of(this.messageTypesList.filter((function(e){return e.name.toUpperCase().includes(t)})))}return c.of(this.messageTypesList)},r.prototype.transformMessageType=function(e){if((e||"").trim()){var t=null,r=e.trim(),n=this.messageTypesList.find((function(e){return e.name===r}));(t=n?{name:n.name,value:n.value}:{name:r,value:r})&&this.addMessageType(t)}this.clear("")},r.prototype.remove=function(e){var t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())},r.prototype.selected=function(e){this.addMessageType(e.option.value),this.clear("")},r.prototype.addMessageType=function(e){-1===this.messageTypes.findIndex((function(t){return t.value===e.value}))&&(this.messageTypes.push(e),this.updateModel())},r.prototype.onFocus=function(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((function(){t.messageTypeInput.nativeElement.blur(),t.messageTypeInput.nativeElement.focus()}),0)},r.prototype.updateModel=function(){var e=this.messageTypes.map((function(e){return e.value}));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:a.TruncatePipe},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),b([t.Input(),h("design:type",String)],r.prototype,"label",void 0),b([t.Input(),h("design:type",Object)],r.prototype,"placeholder",void 0),b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.ViewChild("chipList",{static:!1}),h("design:type",d.MatChipList)],r.prototype,"chipList",void 0),b([t.ViewChild("messageTypeAutocomplete",{static:!1}),h("design:type",p.MatAutocomplete)],r.prototype,"matAutocomplete",void 0),b([t.ViewChild("messageTypeInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"messageTypeInput",void 0),r=l=b([t.Component({selector:"tb-message-types-config",template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return l})),multi:!0}]}),h("design:paramtypes",[o.Store,n.TranslateService,a.TruncatePipe,i.FormBuilder])],r)}(a.PageComponent),le=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.subscriptions=[],n.disableCertPemCredentials=!1,n.allCredentialsTypes=Q,n.credentialsTypeTranslationsMap=_,n.propagateChange=null,n}var n;return y(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.credentialsConfigFormGroup=this.fb.group({type:[null,[i.Validators.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(f.distinctUntilChanged()).subscribe((function(){e.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((function(){e.credentialsTypeChanged()})))},r.prototype.ngOnChanges=function(e){var t,r,n=this;try{for(var a=C(Object.keys(e)),o=a.next();!o.done;o=a.next()){var i=o.value,l=e[i];if(!l.firstChange&&l.currentValue!==l.previousValue)if(l.currentValue&&"disableCertPemCredentials"===i)"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((function(){n.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}catch(e){t={error:e}}finally{try{o&&!o.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}},r.prototype.ngOnDestroy=function(){this.subscriptions.forEach((function(e){return e.unsubscribe()}))},r.prototype.writeValue=function(e){s.isDefinedAndNotNull(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))},r.prototype.setDisabledState=function(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())},r.prototype.updateView=function(){var e=this.credentialsConfigFormGroup.value,t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.validate=function(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}},r.prototype.credentialsTypeChanged=function(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()},r.prototype.updateValidators=function(e){void 0===e&&(e=!1);var t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([i.Validators.required]),this.credentialsConfigFormGroup.get("password").setValidators([i.Validators.required]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(i.Validators.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})},r.prototype.requiredFilesSelected=function(e,t){return void 0===t&&(t=null),function(r){return t||(t=[Object.keys(r.controls)]),(null==r?void 0:r.controls)&&t.some((function(t){return t.every((function(t){return!e(r.controls[t])}))}))?null:{notAllRequiredFilesSelected:!0}}},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),b([t.Input(),h("design:type",Object)],r.prototype,"disableCertPemCredentials",void 0),r=n=b([t.Component({selector:"tb-credentials-config",template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n
\n
\n
\n
\n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),se=function(){function e(){}return e=b([t.NgModule({declarations:[ne,ae,oe,ie,le],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule],exports:[ne,ae,oe,ie,le]})],e)}(),me=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.unassignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-un-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ue=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.snsConfigForm},r.prototype.onConfigurationSet=function(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[i.Validators.required]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-sns-config",template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),de=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.sqsQueueType=j,n.sqsQueueTypes=Object.keys(j),n.sqsQueueTypeTranslationsMap=$,n}return y(r,e),r.prototype.configForm=function(){return this.sqsConfigForm},r.prototype.onConfigurationSet=function(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[i.Validators.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[i.Validators.required]],delaySeconds:[e?e.delaySeconds:null,[i.Validators.min(0),i.Validators.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-sqs-config",template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.pubSubConfigForm},r.prototype.onConfigurationSet=function(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[i.Validators.required]],topicName:[e?e.topicName:null,[i.Validators.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[i.Validators.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[i.Validators.required]],messageAttributes:[e?e.messageAttributes:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-pub-sub-config",template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.ackValues=["all","-1","0","1"],n.ToByteStandartCharsetTypesValues=Y,n.ToByteStandartCharsetTypeTranslationMap=Z,n}return y(r,e),r.prototype.configForm=function(){return this.kafkaConfigForm},r.prototype.onConfigurationSet=function(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],bootstrapServers:[e?e.bootstrapServers:null,[i.Validators.required]],retries:[e?e.retries:null,[i.Validators.min(0)]],batchSize:[e?e.batchSize:null,[i.Validators.min(0)]],linger:[e?e.linger:null,[i.Validators.min(0)]],bufferMemory:[e?e.bufferMemory:null,[i.Validators.min(0)]],acks:[e?e.acks:null,[i.Validators.required]],keySerializer:[e?e.keySerializer:null,[i.Validators.required]],valueSerializer:[e?e.valueSerializer:null,[i.Validators.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})},r.prototype.validatorTriggers=function(){return["addMetadataKeyValuesAsKafkaHeaders"]},r.prototype.updateValidators=function(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([i.Validators.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-kafka-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.mqttConfigForm},r.prototype.onConfigurationSet=function(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-mqtt-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n \n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],n}return y(r,e),r.prototype.configForm=function(){return this.rabbitMqConfigForm},r.prototype.onConfigurationSet=function(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[i.Validators.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[i.Validators.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rabbit-mq-config",template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ye=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.proxySchemes=["http","https"],n.httpRequestTypes=Object.keys(z),n}return y(r,e),r.prototype.configForm=function(){return this.restApiCallConfigForm},r.prototype.onConfigurationSet=function(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[i.Validators.required]],requestMethod:[e?e.requestMethod:null,[i.Validators.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[i.Validators.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})},r.prototype.validatorTriggers=function(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]},r.prototype.updateValidators=function(e){var t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,r=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,n=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;n&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(n?[i.Validators.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(n?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([i.Validators.min(0)])),r?this.restApiCallConfigForm.get("maxQueueSize").setValidators([i.Validators.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rest-api-call-config",template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n \n \n \n tb.rulenode.max-parallel-requests-count\n \n \n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.smtpProtocols=["smtp","smtps"],n.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"],n}return y(r,e),r.prototype.configForm=function(){return this.sendEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmtpSettings","enableProxy"]},r.prototype.updateValidators=function(e){var t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,r=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([i.Validators.required,i.Validators.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(r?[i.Validators.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(r?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-send-email-config",template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),he=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.serviceType=a.ServiceType.TB_RULE_ENGINE,n}return y(r,e),r.prototype.configForm=function(){return this.checkPointConfigForm},r.prototype.onConfigurationSet=function(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-check-point-config",template:'
\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allAzureIotHubCredentialsTypes=W,n.azureIotHubCredentialsTypeTranslationsMap=J,n}return y(r,e),r.prototype.configForm=function(){return this.azureIotHubConfigForm},r.prototype.onConfigurationSet=function(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[i.Validators.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[i.Validators.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})},r.prototype.prepareOutputConfig=function(e){var t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e},r.prototype.validatorTriggers=function(){return["credentials.type"]},r.prototype.updateValidators=function(e){var t=this.azureIotHubConfigForm.get("credentials"),r=t.get("type").value;switch(e&&t.reset({type:r},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),r){case"sas":t.get("sasKey").setValidators([i.Validators.required]);break;case"cert.PEM":t.get("privateKey").setValidators([i.Validators.required]),t.get("privateKeyFileName").setValidators([i.Validators.required]),t.get("cert").setValidators([i.Validators.required]),t.get("certFileName").setValidators([i.Validators.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-azure-iot-hub-config",template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.deviceProfile},r.prototype.onConfigurationSet=function(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,i.Validators.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,i.Validators.required]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-device-profile-config",template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.sendSmsConfigForm},r.prototype.onConfigurationSet=function(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[i.Validators.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[i.Validators.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmsSettings"]},r.prototype.updateValidators=function(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([i.Validators.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-send-sms-config",template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),xe=function(){function e(){}return e=b([t.NgModule({declarations:[x,T,q,S,I,k,N,V,E,A,L,X,ee,te,re,me,ue,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule,se],exports:[x,T,q,S,I,k,N,V,E,A,L,X,ee,te,re,me,ue,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe]})],e)}(),Te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.checkMessageConfigForm},r.prototype.onConfigurationSet=function(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})},r.prototype.validateConfig=function(){var e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0},r.prototype.removeMessageName=function(e){var t=this.checkMessageConfigForm.get("messageNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))},r.prototype.removeMetadataName=function(e){var t=this.checkMessageConfigForm.get("metadataNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))},r.prototype.addMessageName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("messageNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("messageNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.prototype.addMetadataName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("metadataNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("metadataNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-check-message-config",template:'
\n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),qe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.entitySearchDirection=Object.keys(a.EntitySearchDirection),n.entitySearchDirectionTranslationsMap=a.entitySearchDirectionTranslations,n}return y(r,e),r.prototype.configForm=function(){return this.checkRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],relationType:[e?e.relationType:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["checkForSingleEntity"]},r.prototype.updateValidators=function(e){var t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-check-relation-config",template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=R,n.rangeUnits=Object.keys(D),n.rangeUnitTranslationMap=B,n}return y(r,e),r.prototype.configForm=function(){return this.geoFilterConfigForm},r.prototype.onConfigurationSet=function(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterType").setValidators([]):this.geoFilterConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoFilterConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoFilterConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ie=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.messageTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-message-type-config",template:'
\n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allowedEntityTypes=[a.EntityType.DEVICE,a.EntityType.ASSET,a.EntityType.ENTITY_VIEW,a.EntityType.TENANT,a.EntityType.CUSTOMER,a.EntityType.USER,a.EntityType.DASHBOARD,a.EntityType.RULE_CHAIN,a.EntityType.RULE_NODE],n}return y(r,e),r.prototype.configForm=function(){return this.originatorTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-originator-type-config",template:'
\n \n \n \n
\n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ne=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-filter-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Ve=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.switchConfigForm},r.prototype.onConfigurationSet=function(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.switchConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-filter-node-switch-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Ee=function(e){function r(t,r,n){var o,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.fb=n,s.alarmStatusTranslationsMap=a.alarmStatusTranslations,s.alarmStatusList=[],s.searchText="",s.displayStatusFn=s.displayStatus.bind(s);try{for(var m=C(Object.keys(a.AlarmStatus)),u=m.next();!u.done;u=m.next()){var d=u.value;s.alarmStatusList.push(a.AlarmStatus[d])}}catch(e){o={error:e}}finally{try{u&&!u.done&&(l=m.return)&&l.call(m)}finally{if(o)throw o.error}}return s.statusFormControl=new i.FormControl(""),s.filteredAlarmStatus=s.statusFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return s.fetchAlarmStatus(e)})),f.share()),s}return y(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.alarmStatusConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[i.Validators.required]]})},r.prototype.displayStatus=function(e){return e?this.translate.instant(a.alarmStatusTranslations.get(e)):void 0},r.prototype.fetchAlarmStatus=function(e){var t=this,r=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){var n=this.searchText.toUpperCase();return c.of(r.filter((function(e){return t.translate.instant(a.alarmStatusTranslations.get(a.AlarmStatus[e])).toUpperCase().includes(n)})))}return c.of(r)},r.prototype.alarmStatusSelected=function(e){this.addAlarmStatus(e.option.value),this.clear("")},r.prototype.removeAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}},r.prototype.addAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))},r.prototype.getAlarmStatusList=function(){var e=this;return this.alarmStatusList.filter((function(t){return-1===e.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(t)}))},r.prototype.onAlarmStatusInputFocus=function(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.alarmStatusInput.nativeElement.blur(),t.alarmStatusInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},b([t.ViewChild("alarmStatusInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"alarmStatusInput",void 0),r=b([t.Component({selector:"tb-filter-node-check-alarm-status-config",template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n'}),h("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ae=function(){function e(){}return e=b([t.NgModule({declarations:[Te,qe,Se,Ie,ke,Ne,Ve,Ee],imports:[r.CommonModule,a.SharedModule,se],exports:[Te,qe,Se,Ie,ke,Ne,Ve,Ee]})],e)}(),Le=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.customerAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-customer-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Me=function(e){function r(t,r,n){var a,o,l=e.call(this,t)||this;l.store=t,l.translate=r,l.fb=n,l.entityDetailsTranslationsMap=H,l.entityDetailsList=[],l.searchText="",l.displayDetailsFn=l.displayDetails.bind(l);try{for(var s=C(Object.keys(K)),m=s.next();!m.done;m=s.next()){var u=m.value;l.entityDetailsList.push(K[u])}}catch(e){a={error:e}}finally{try{m&&!m.done&&(o=s.return)&&o.call(s)}finally{if(a)throw a.error}}return l.detailsFormControl=new i.FormControl(""),l.filteredEntityDetails=l.detailsFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return l.fetchEntityDetails(e)})),f.share()),l}return y(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.entityDetailsConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[i.Validators.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})},r.prototype.displayDetails=function(e){return e?this.translate.instant(H.get(e)):void 0},r.prototype.fetchEntityDetails=function(e){var t=this;if(this.searchText=e,this.searchText&&this.searchText.length){var r=this.searchText.toUpperCase();return c.of(this.entityDetailsList.filter((function(e){return t.translate.instant(H.get(K[e])).toUpperCase().includes(r)})))}return c.of(this.entityDetailsList)},r.prototype.detailsFieldSelected=function(e){this.addDetailsField(e.option.value),this.clear("")},r.prototype.removeDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}},r.prototype.addDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))},r.prototype.onEntityDetailsInputFocus=function(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.detailsInput.nativeElement.blur(),t.detailsInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},b([t.ViewChild("detailsInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"detailsInput",void 0),r=b([t.Component({selector:"tb-enrichment-node-entity-details-config",template:'
\n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-entity-details-matching\n
\n
\n
\n
\n
\n \n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
tb.rulenode.add-to-metadata-hint
\n
\n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}"]}),h("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.deviceAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[i.Validators.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.deviceAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.deviceAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.deviceAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.deviceAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-device-attributes-config",template:'
\n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),we=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.originatorAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.originatorAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.originatorAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.originatorAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.originatorAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-originator-attributes-config",template:'
\n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.originatorFieldsConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-originator-fields-config",template:'
\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),De=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n.fetchMode=G,n.fetchModes=Object.keys(G),n.samplingOrders=Object.keys(U),n.timeUnits=Object.keys(w),n.timeUnitsTranslationMap=O,n}return y(r,e),r.prototype.configForm=function(){return this.getTelemetryFromDatabaseConfigForm},r.prototype.onConfigurationSet=function(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],fetchMode:[e?e.fetchMode:null,[i.Validators.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchMode","useMetadataIntervalPatterns"]},r.prototype.updateValidators=function(e){var t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,r=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===G.ALL?(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([i.Validators.required,i.Validators.min(2),i.Validators.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),r?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([i.Validators.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})},r.prototype.removeKey=function(e,t){var r=this.getTelemetryFromDatabaseConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.getTelemetryFromDatabaseConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-get-telemetry-from-database",template:'
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
\n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
\n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-interval-patterns-hint
\n
\n
\n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.relatedAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[i.Validators.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-related-attributes-config",template:'
\n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.tenantAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-tenant-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.calculateDeltaConfigForm},r.prototype.onConfigurationSet=function(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e?e.inputValueKey:null,[i.Validators.required]],outputValueKey:[e?e.outputValueKey:null,[i.Validators.required]],useCache:[e?e.useCache:null,[]],addPeriodBetweenMsgs:[!!e&&e.addPeriodBetweenMsgs,[]],periodValueKey:[e?e.periodValueKey:null,[]],round:[e?e.round:null,[i.Validators.min(0),i.Validators.max(15)]],tellFailureIfInputValueKeyIsAbsent:[e?e.tellFailureIfInputValueKeyIsAbsent:null,[]],tellFailureIfDeltaIsNegative:[e?e.tellFailureIfDeltaIsNegative:null,[]]})},r.prototype.updateValidators=function(e){console.log("updateValidators"),this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?(console.log("true"),this.calculateDeltaConfigForm.get("periodValueKey").setValidators([i.Validators.required])):(console.log("false"),this.calculateDeltaConfigForm.get("periodValueKey").setValidators([])),this.calculateDeltaConfigForm.get("inputValueKey").updateValueAndValidity({emitEvent:e}),this.calculateDeltaConfigForm.get("outputValueKey").updateValueAndValidity({emitEvent:e}),this.calculateDeltaConfigForm.get("round").updateValueAndValidity({emitEvent:e}),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})},r.prototype.validatorTriggers=function(){return["addPeriodBetweenMsgs"]},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-calculate-delta-config",template:'
\n
\n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-input-value-key-is-absent\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ge=function(){function e(){}return e=b([t.NgModule({declarations:[Le,Me,Pe,we,Re,De,Oe,Ke,Be],imports:[r.CommonModule,a.SharedModule,se],exports:[Le,Me,Pe,we,Re,De,Oe,Ke,Be]})],e)}(),Ue=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.originatorSource=v,n.originatorSources=Object.keys(v),n.originatorSourceTranslationMap=P,n}return y(r,e),r.prototype.configForm=function(){return this.changeOriginatorConfigForm},r.prototype.onConfigurationSet=function(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[i.Validators.required]],relationsQuery:[e?e.relationsQuery:null,[]]})},r.prototype.validatorTriggers=function(){return["originatorSource"]},r.prototype.updateValidators=function(e){var t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===v.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([i.Validators.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-transformation-node-change-originator-config",template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),je=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-transformation-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),He=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.toEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[i.Validators.required]],toTemplate:[e?e.toTemplate:null,[i.Validators.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[i.Validators.required]],bodyTemplate:[e?e.bodyTemplate:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-transformation-node-to-email-config",template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ze=function(){function e(){}return e=b([t.NgModule({declarations:[Ue,je,He],imports:[r.CommonModule,a.SharedModule,se],exports:[Ue,je,He]})],e)}(),$e=function(){function e(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-name-pattern-hint":"Name pattern, use ${metaKeyName} to substitute variables from metadata","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-type-pattern-hint":"Type pattern, use ${metaKeyName} to substitute variables from metadata","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-name-pattern-hint":"Customer name pattern, use ${metaKeyName} to substitute variables from metadata","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","client-attributes-hint":"Client attributes, use ${metaKeyName} to substitute variables from metadata","shared-attributes":"Shared attributes","shared-attributes-hint":"Shared attributes, use ${metaKeyName} to substitute variables from metadata","server-attributes":"Server attributes","server-attributes-hint":"Server attributes, use ${metaKeyName} to substitute variables from metadata","notify-device":"Notify Device","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","latest-timeseries":"Latest timeseries","latest-timeseries-hint":"Latest timeseries, use ${metaKeyName} to substitute variables from metadata","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-hint":"Relation type pattern, use ${metaKeyName} to substitute variables from metadata","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use metadata period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds metadata pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","period-in-seconds-pattern-hint":"Period in seconds pattern, use ${metaKeyName} to substitute variables from metadata","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","from-template-hint":"From address template, use ${metaKeyName} to substitute variables from metadata","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":"Comma separated address list, use ${metaKeyName} to substitute variables from metadata","cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","subject-template-hint":"Mail subject template, use ${metaKeyName} to substitute variables from metadata","body-template":"Body Template","body-template-required":"Body Template is required","body-template-hint":"Mail body template, use ${metaKeyName} to substitute variables from metadata","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","endpoint-url-pattern-hint":"HTTP URL address pattern, use ${metaKeyName} to substitute variables from metadata","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":"Use ${metaKeyName} in header/value fields to substitute variables from metadata",header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required","mqtt-topic-pattern-hint":"MQTT topic pattern, use ${metaKeyName} to substitute variables from metadata",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","topic-arn-pattern-hint":"Topic ARN pattern, use ${metaKeyName} to substitute variables from metadata","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","queue-url-pattern-hint":"Queue URL pattern, use ${metaKeyName} to substitute variables from metadata","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":"Use ${metaKeyName} in name/value fields to substitute variables from metadata","connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file *","private-key":"Client private key file *",cert:"Client certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use metadata interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","start-interval-pattern-hint":"Start interval pattern, use ${metaKeyName} to substitute variables from metadata","end-interval-pattern-hint":"End interval pattern, use ${metaKeyName} to substitute variables from metadata","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":"Comma separated Phone Numbers, use ${metaKeyName} to substitute variables from metadata","sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","sms-message-template-hint":"SMS message template, use ${metaKeyName} to substitute variables from metadata","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-zip":"Zip","entity-details-address":"Address","entity-details-address2":"Address2","entity-details-additional_info":"Additional Info","entity-details-phone":"Phone","entity-details-email":"Email","add-to-metadata":"Add selected details to message metadata","add-to-metadata-hint":"If selected, adds the selected details keys to the message metadata instead of message data.","entity-details-list-empty":"No entity details selected.","no-entity-details-matching":"No entity details matching were found.","custom-table-name":"Custom table name","custom-table-name-required":"Table Name is required","custom-table-hint":"You should enter the table name without prefix 'cs_tb_'.","message-field":"Message field","message-field-required":"Message field is required.","table-col":"Table column","table-col-required":"Table column is required.","latitude-key-name":"Latitude key name","longitude-key-name":"Longitude key name","latitude-key-name-required":"Latitude key name is required.","longitude-key-name-required":"Longitude key name is required.","fetch-perimeter-info-from-message-metadata":"Fetch perimeter information from message metadata","perimeter-circle":"Circle","perimeter-polygon":"Polygon","perimeter-type":"Perimeter type","circle-center-latitude":"Center latitude","circle-center-latitude-required":"Center latitude is required.","circle-center-longitude":"Center longitude","circle-center-longitude-required":"Center longitude is required.","range-unit-meter":"Meter","range-unit-kilometer":"Kilometer","range-unit-foot":"Foot","range-unit-mile":"Mile","range-unit-nautical-mile":"Nautical mile","range-units":"Range units",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].","min-inside-duration":"Minimal inside duration","min-inside-duration-value-required":"Minimal inside duration is required","min-inside-duration-time-unit":"Minimal inside duration time unit","min-outside-duration":"Minimal outside duration","min-outside-duration-value-required":"Minimal outside duration is required","min-outside-duration-time-unit":"Minimal outside duration time unit","tell-failure-if-absent":"Tell Failure","tell-failure-if-absent-hint":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"get-latest-value-with-ts":"Fetch Latest telemetry with Timestamp","get-latest-value-with-ts-hint":'If selected, latest telemetry values will be added to the outbound message metadata with timestamp, e.g: "temp": "{\\"ts\\":1574329385897,\\"value\\":42}"',"use-redis-queue":"Use redis queue for message persistence","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required.","output-value-key":"Output value key","output-value-key-required":"Output value key is required.",round:"Decimals","round-range":"Decimals should be in a range from 0 to 15.","use-cache":"Use cache for latest value","tell-failure-if-input-value-key-is-absent":"Tell Failure if input value key is absent","tell-failure-if-delta-is-negative":"Tell Failure if delta is negative","add-period-between-msgs":"Add period between messages","period-value-key":"Period value key","period-key-required":"Period value key is required."},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"}}},!0)}(e)}return e.ctorParameters=function(){return[{type:n.TranslateService}]},e=b([t.NgModule({declarations:[F],imports:[r.CommonModule,a.SharedModule],exports:[xe,Ae,Ge,ze,F]}),h("design:paramtypes",[n.TranslateService])],e)}();e.RuleNodeCoreConfigModule=$e,e.ɵa=F,e.ɵb=xe,e.ɵba=he,e.ɵbb=Ce,e.ɵbc=ve,e.ɵbd=Fe,e.ɵbe=se,e.ɵbf=ne,e.ɵbg=ae,e.ɵbh=oe,e.ɵbi=ie,e.ɵbj=le,e.ɵbk=Ae,e.ɵbl=Te,e.ɵbm=qe,e.ɵbn=Se,e.ɵbo=Ie,e.ɵbp=ke,e.ɵbq=Ne,e.ɵbr=Ve,e.ɵbs=Ee,e.ɵbt=Ge,e.ɵbu=Le,e.ɵbv=Me,e.ɵbw=Pe,e.ɵbx=we,e.ɵby=Re,e.ɵbz=De,e.ɵc=x,e.ɵca=Oe,e.ɵcb=Ke,e.ɵcc=Be,e.ɵcd=ze,e.ɵce=Ue,e.ɵcf=je,e.ɵcg=He,e.ɵd=T,e.ɵe=q,e.ɵf=S,e.ɵg=I,e.ɵh=k,e.ɵi=N,e.ɵj=V,e.ɵk=E,e.ɵl=A,e.ɵm=L,e.ɵn=X,e.ɵo=ee,e.ɵp=te,e.ɵq=re,e.ɵr=me,e.ɵs=ue,e.ɵt=de,e.ɵu=pe,e.ɵv=ce,e.ɵw=fe,e.ɵx=ge,e.ɵy=ye,e.ɵz=be,Object.defineProperty(e,"__esModule",{value:!0})})); //# sourceMappingURL=rulenode-core-config.umd.min.js.map \ No newline at end of file From 6625d0d6163311226ddb0a75c97d11bbcb917c8f Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 3 Feb 2021 16:06:00 +0200 Subject: [PATCH 111/249] refactoring --- .../resources/public/static/rulenode/rulenode-core-config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js index 50f08c8425..b747cd797d 100644 --- a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js +++ b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js @@ -12,5 +12,5 @@ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - ***************************************************************************** */var g=function(e,t){return(g=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])})(e,t)};function y(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}g(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}function b(e,t,r,n){var a,o=arguments.length,i=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,r,n);else for(var l=e.length-1;l>=0;l--)(a=e[l])&&(i=(o<3?a(i):o>3?a(t,r,i):a(t,r))||i);return o>3&&i&&Object.defineProperty(t,r,i),i}function h(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}Object.create;function C(e){var t="function"==typeof Symbol&&Symbol.iterator,r=t&&e[t],n=0;if(r)return r.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}Object.create;var v,F=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.emptyConfigForm},r.prototype.onConfigurationSet=function(e){this.emptyConfigForm=this.fb.group({})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-node-empty-config",template:"
"}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),x=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return y(r,e),r.prototype.configForm=function(){return this.attributesConfigForm},r.prototype.onConfigurationSet=function(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]],notifyDevice:[!e||e.scope,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-attributes-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),T=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.timeseriesConfigForm},r.prototype.onConfigurationSet=function(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-timeseries-config",template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),q=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.rpcRequestConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rpc-request-config",template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),S=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.logConfigForm},r.prototype.onConfigurationSet=function(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.logConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-log-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),I=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.assignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),k=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.clearAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],alarmType:[e?e.alarmType:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-clear-alarm-config",template:'
\n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),N=function(e){function r(t,r,n,o){var i=e.call(this,t)||this;return i.store=t,i.fb=r,i.nodeScriptTestService=n,i.translate=o,i.alarmSeverities=Object.keys(a.AlarmSeverity),i.alarmSeverityTranslationMap=a.alarmSeverityTranslations,i.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],i}return y(r,e),r.prototype.configForm=function(){return this.createAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]]})},r.prototype.validatorTriggers=function(){return["useMessageAlarmData"]},r.prototype.updateValidators=function(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([i.Validators.required]),this.createAlarmConfigForm.get("severity").setValidators([i.Validators.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})},r.prototype.testScript=function(){var e=this,t=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.removeKey=function(e,t){var r=this.createAlarmConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.createAlarmConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.createAlarmConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.createAlarmConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-create-alarm-config",template:'
\n \n \n \n
\n \n
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n \n \n
\n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),V=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return y(r,e),r.prototype.configForm=function(){return this.createRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[i.Validators.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["entityType"]},r.prototype.updateValidators=function(e){var t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==a.EntityType.DEVICE&&t!==a.EntityType.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([i.Validators.required]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-create-relation-config",template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),E=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.msgDelayConfigForm},r.prototype.onConfigurationSet=function(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(1e5)]]})},r.prototype.validatorTriggers=function(){return["useMetadataPeriodInSecondsPatterns"]},r.prototype.updateValidators=function(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([i.Validators.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([i.Validators.required,i.Validators.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-msg-delay-config",template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),A=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return y(r,e),r.prototype.configForm=function(){return this.deleteRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["deleteForSingleEntity","entityType"]},r.prototype.updateValidators=function(e){var t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,r=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&r?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-delete-relation-config",template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),L=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.generatorConfigForm},r.prototype.onConfigurationSet=function(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[i.Validators.required,i.Validators.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[i.Validators.required,i.Validators.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.prepareInputConfig=function(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e},r.prototype.prepareOutputConfig=function(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e},r.prototype.testScript=function(){var e=this,t=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId).subscribe((function(t){t&&e.generatorConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-generator-config",template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent);!function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(v||(v={}));var M,P=new Map([[v.CUSTOMER,"tb.rulenode.originator-customer"],[v.TENANT,"tb.rulenode.originator-tenant"],[v.RELATED,"tb.rulenode.originator-related"],[v.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(M||(M={}));var w,R=new Map([[M.CIRCLE,"tb.rulenode.perimeter-circle"],[M.POLYGON,"tb.rulenode.perimeter-polygon"]]);!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(w||(w={}));var D,O=new Map([[w.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[w.SECONDS,"tb.rulenode.time-unit-seconds"],[w.MINUTES,"tb.rulenode.time-unit-minutes"],[w.HOURS,"tb.rulenode.time-unit-hours"],[w.DAYS,"tb.rulenode.time-unit-days"]]);!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(D||(D={}));var K,B=new Map([[D.METER,"tb.rulenode.range-unit-meter"],[D.KILOMETER,"tb.rulenode.range-unit-kilometer"],[D.FOOT,"tb.rulenode.range-unit-foot"],[D.MILE,"tb.rulenode.range-unit-mile"],[D.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(K||(K={}));var G,U,j,H=new Map([[K.TITLE,"tb.rulenode.entity-details-title"],[K.COUNTRY,"tb.rulenode.entity-details-country"],[K.STATE,"tb.rulenode.entity-details-state"],[K.ZIP,"tb.rulenode.entity-details-zip"],[K.ADDRESS,"tb.rulenode.entity-details-address"],[K.ADDRESS2,"tb.rulenode.entity-details-address2"],[K.PHONE,"tb.rulenode.entity-details-phone"],[K.EMAIL,"tb.rulenode.entity-details-email"],[K.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(G||(G={})),function(e){e.ASC="ASC",e.DESC="DESC"}(U||(U={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(j||(j={}));var z,$=new Map([[j.STANDARD,"tb.rulenode.sqs-queue-standard"],[j.FIFO,"tb.rulenode.sqs-queue-fifo"]]),Q=["anonymous","basic","cert.PEM"],_=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),W=["sas","cert.PEM"],J=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(z||(z={}));var Y=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],Z=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]),X=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=R,n.rangeUnits=Object.keys(D),n.rangeUnitTranslationMap=B,n.timeUnits=Object.keys(w),n.timeUnitsTranslationMap=O,n}return y(r,e),r.prototype.configForm=function(){return this.geoActionConfigForm},r.prototype.onConfigurationSet=function(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[i.Validators.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterType").setValidators([]):this.geoActionConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoActionConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoActionConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.msgCountConfigForm},r.prototype.onConfigurationSet=function(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[i.Validators.required,i.Validators.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-msg-count-config",template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.rpcReplyConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rpc-reply-config",template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.saveToCustomTableConfigForm},r.prototype.onConfigurationSet=function(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[i.Validators.required]],fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-custom-table-config",template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n \n \n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ne=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.translate=r,o.injector=n,o.fb=a,o.propagateChange=null,o.valueChangeSubscription=null,o}var a;return y(r,e),a=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){this.ngControl=this.injector.get(i.NgControl),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))},r.prototype.keyValsFormArray=function(){return this.kvListFormGroup.get("keyVals")},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t,r,n=this;this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();var a=[];if(e)try{for(var o=C(Object.keys(e)),l=o.next();!l.done;l=o.next()){var s=l.value;Object.prototype.hasOwnProperty.call(e,s)&&a.push(this.fb.group({key:[s,[i.Validators.required]],value:[e[s],[i.Validators.required]]}))}}catch(e){t={error:e}}finally{try{l&&!l.done&&(r=o.return)&&r.call(o)}finally{if(t)throw t.error}}this.kvListFormGroup.setControl("keyVals",this.fb.array(a)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((function(){n.updateModel()}))},r.prototype.removeKeyVal=function(e){this.kvListFormGroup.get("keyVals").removeAt(e)},r.prototype.addKeyVal=function(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[i.Validators.required]],value:["",[i.Validators.required]]}))},r.prototype.validate=function(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}},r.prototype.updateModel=function(){var e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{var t={};e.forEach((function(e){t[e.key]=e.value})),this.propagateChange(t)}},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:t.Injector},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",String)],r.prototype,"requiredText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"keyText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"keyRequiredText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"valText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"valRequiredText",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=a=b([t.Component({selector:"tb-kv-map-config",template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n \n
\n \n
\n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return a})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return a})),multi:!0}],styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:rgba(0,0,0,.54);font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}"]}),h("design:paramtypes",[o.Store,n.TranslateService,t.Injector,i.FormBuilder])],r)}(a.PageComponent),ae=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n.propagateChange=null,n}var n;return y(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[i.Validators.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((function(t){e.deviceRelationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=b([t.Component({selector:"tb-device-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-type
\n \n \n
device.device-types
\n \n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.propagateChange=null,n}var n;return y(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((function(t){e.relationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=b([t.Component({selector:"tb-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),ie=function(e){function r(t,r,n,o){var i,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.truncate=n,s.fb=o,s.placeholder="tb.rulenode.message-type",s.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],s.messageTypes=[],s.messageTypesList=[],s.searchText="",s.propagateChange=function(e){},s.messageTypeConfigForm=s.fb.group({messageType:[null]});try{for(var u=C(Object.keys(a.MessageType)),d=u.next();!d.done;d=u.next()){var p=d.value;s.messageTypesList.push({name:a.messageTypeNames.get(a.MessageType[p]),value:p})}}catch(e){i={error:e}}finally{try{d&&!d.done&&(l=u.return)&&l.call(u)}finally{if(i)throw i.error}}return s}var l;return y(r,e),l=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.ngOnInit=function(){var e=this;this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(t){return e.fetchMessageTypes(t)})),f.share())},r.prototype.ngAfterViewInit=function(){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t=this;this.searchText="",this.messageTypes.length=0,e&&e.forEach((function(e){var r=t.messageTypesList.find((function(t){return t.value===e}));r?t.messageTypes.push({name:r.name,value:r.value}):t.messageTypes.push({name:e,value:e})}))},r.prototype.displayMessageTypeFn=function(e){return e?e.name:void 0},r.prototype.textIsNotEmpty=function(e){return!!(e&&null!=e&&e.length>0)},r.prototype.createMessageType=function(e,t){e.preventDefault(),this.transformMessageType(t)},r.prototype.add=function(e){this.transformMessageType(e.value)},r.prototype.fetchMessageTypes=function(e){if(this.searchText=e,this.searchText&&this.searchText.length){var t=this.searchText.toUpperCase();return c.of(this.messageTypesList.filter((function(e){return e.name.toUpperCase().includes(t)})))}return c.of(this.messageTypesList)},r.prototype.transformMessageType=function(e){if((e||"").trim()){var t=null,r=e.trim(),n=this.messageTypesList.find((function(e){return e.name===r}));(t=n?{name:n.name,value:n.value}:{name:r,value:r})&&this.addMessageType(t)}this.clear("")},r.prototype.remove=function(e){var t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())},r.prototype.selected=function(e){this.addMessageType(e.option.value),this.clear("")},r.prototype.addMessageType=function(e){-1===this.messageTypes.findIndex((function(t){return t.value===e.value}))&&(this.messageTypes.push(e),this.updateModel())},r.prototype.onFocus=function(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((function(){t.messageTypeInput.nativeElement.blur(),t.messageTypeInput.nativeElement.focus()}),0)},r.prototype.updateModel=function(){var e=this.messageTypes.map((function(e){return e.value}));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:a.TruncatePipe},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),b([t.Input(),h("design:type",String)],r.prototype,"label",void 0),b([t.Input(),h("design:type",Object)],r.prototype,"placeholder",void 0),b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.ViewChild("chipList",{static:!1}),h("design:type",d.MatChipList)],r.prototype,"chipList",void 0),b([t.ViewChild("messageTypeAutocomplete",{static:!1}),h("design:type",p.MatAutocomplete)],r.prototype,"matAutocomplete",void 0),b([t.ViewChild("messageTypeInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"messageTypeInput",void 0),r=l=b([t.Component({selector:"tb-message-types-config",template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return l})),multi:!0}]}),h("design:paramtypes",[o.Store,n.TranslateService,a.TruncatePipe,i.FormBuilder])],r)}(a.PageComponent),le=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.subscriptions=[],n.disableCertPemCredentials=!1,n.allCredentialsTypes=Q,n.credentialsTypeTranslationsMap=_,n.propagateChange=null,n}var n;return y(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.credentialsConfigFormGroup=this.fb.group({type:[null,[i.Validators.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(f.distinctUntilChanged()).subscribe((function(){e.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((function(){e.credentialsTypeChanged()})))},r.prototype.ngOnChanges=function(e){var t,r,n=this;try{for(var a=C(Object.keys(e)),o=a.next();!o.done;o=a.next()){var i=o.value,l=e[i];if(!l.firstChange&&l.currentValue!==l.previousValue)if(l.currentValue&&"disableCertPemCredentials"===i)"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((function(){n.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}catch(e){t={error:e}}finally{try{o&&!o.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}},r.prototype.ngOnDestroy=function(){this.subscriptions.forEach((function(e){return e.unsubscribe()}))},r.prototype.writeValue=function(e){s.isDefinedAndNotNull(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))},r.prototype.setDisabledState=function(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())},r.prototype.updateView=function(){var e=this.credentialsConfigFormGroup.value,t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.validate=function(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}},r.prototype.credentialsTypeChanged=function(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()},r.prototype.updateValidators=function(e){void 0===e&&(e=!1);var t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([i.Validators.required]),this.credentialsConfigFormGroup.get("password").setValidators([i.Validators.required]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(i.Validators.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})},r.prototype.requiredFilesSelected=function(e,t){return void 0===t&&(t=null),function(r){return t||(t=[Object.keys(r.controls)]),(null==r?void 0:r.controls)&&t.some((function(t){return t.every((function(t){return!e(r.controls[t])}))}))?null:{notAllRequiredFilesSelected:!0}}},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),b([t.Input(),h("design:type",Object)],r.prototype,"disableCertPemCredentials",void 0),r=n=b([t.Component({selector:"tb-credentials-config",template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n
\n
\n
\n
\n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),se=function(){function e(){}return e=b([t.NgModule({declarations:[ne,ae,oe,ie,le],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule],exports:[ne,ae,oe,ie,le]})],e)}(),me=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.unassignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-un-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ue=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.snsConfigForm},r.prototype.onConfigurationSet=function(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[i.Validators.required]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-sns-config",template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),de=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.sqsQueueType=j,n.sqsQueueTypes=Object.keys(j),n.sqsQueueTypeTranslationsMap=$,n}return y(r,e),r.prototype.configForm=function(){return this.sqsConfigForm},r.prototype.onConfigurationSet=function(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[i.Validators.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[i.Validators.required]],delaySeconds:[e?e.delaySeconds:null,[i.Validators.min(0),i.Validators.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-sqs-config",template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.pubSubConfigForm},r.prototype.onConfigurationSet=function(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[i.Validators.required]],topicName:[e?e.topicName:null,[i.Validators.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[i.Validators.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[i.Validators.required]],messageAttributes:[e?e.messageAttributes:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-pub-sub-config",template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.ackValues=["all","-1","0","1"],n.ToByteStandartCharsetTypesValues=Y,n.ToByteStandartCharsetTypeTranslationMap=Z,n}return y(r,e),r.prototype.configForm=function(){return this.kafkaConfigForm},r.prototype.onConfigurationSet=function(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],bootstrapServers:[e?e.bootstrapServers:null,[i.Validators.required]],retries:[e?e.retries:null,[i.Validators.min(0)]],batchSize:[e?e.batchSize:null,[i.Validators.min(0)]],linger:[e?e.linger:null,[i.Validators.min(0)]],bufferMemory:[e?e.bufferMemory:null,[i.Validators.min(0)]],acks:[e?e.acks:null,[i.Validators.required]],keySerializer:[e?e.keySerializer:null,[i.Validators.required]],valueSerializer:[e?e.valueSerializer:null,[i.Validators.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})},r.prototype.validatorTriggers=function(){return["addMetadataKeyValuesAsKafkaHeaders"]},r.prototype.updateValidators=function(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([i.Validators.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-kafka-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.mqttConfigForm},r.prototype.onConfigurationSet=function(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-mqtt-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n \n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],n}return y(r,e),r.prototype.configForm=function(){return this.rabbitMqConfigForm},r.prototype.onConfigurationSet=function(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[i.Validators.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[i.Validators.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rabbit-mq-config",template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ye=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.proxySchemes=["http","https"],n.httpRequestTypes=Object.keys(z),n}return y(r,e),r.prototype.configForm=function(){return this.restApiCallConfigForm},r.prototype.onConfigurationSet=function(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[i.Validators.required]],requestMethod:[e?e.requestMethod:null,[i.Validators.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[i.Validators.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})},r.prototype.validatorTriggers=function(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]},r.prototype.updateValidators=function(e){var t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,r=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,n=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;n&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(n?[i.Validators.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(n?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([i.Validators.min(0)])),r?this.restApiCallConfigForm.get("maxQueueSize").setValidators([i.Validators.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rest-api-call-config",template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n \n \n \n tb.rulenode.max-parallel-requests-count\n \n \n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.smtpProtocols=["smtp","smtps"],n.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"],n}return y(r,e),r.prototype.configForm=function(){return this.sendEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmtpSettings","enableProxy"]},r.prototype.updateValidators=function(e){var t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,r=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([i.Validators.required,i.Validators.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(r?[i.Validators.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(r?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-send-email-config",template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),he=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.serviceType=a.ServiceType.TB_RULE_ENGINE,n}return y(r,e),r.prototype.configForm=function(){return this.checkPointConfigForm},r.prototype.onConfigurationSet=function(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-check-point-config",template:'
\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allAzureIotHubCredentialsTypes=W,n.azureIotHubCredentialsTypeTranslationsMap=J,n}return y(r,e),r.prototype.configForm=function(){return this.azureIotHubConfigForm},r.prototype.onConfigurationSet=function(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[i.Validators.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[i.Validators.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})},r.prototype.prepareOutputConfig=function(e){var t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e},r.prototype.validatorTriggers=function(){return["credentials.type"]},r.prototype.updateValidators=function(e){var t=this.azureIotHubConfigForm.get("credentials"),r=t.get("type").value;switch(e&&t.reset({type:r},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),r){case"sas":t.get("sasKey").setValidators([i.Validators.required]);break;case"cert.PEM":t.get("privateKey").setValidators([i.Validators.required]),t.get("privateKeyFileName").setValidators([i.Validators.required]),t.get("cert").setValidators([i.Validators.required]),t.get("certFileName").setValidators([i.Validators.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-azure-iot-hub-config",template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.deviceProfile},r.prototype.onConfigurationSet=function(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,i.Validators.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,i.Validators.required]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-device-profile-config",template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.sendSmsConfigForm},r.prototype.onConfigurationSet=function(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[i.Validators.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[i.Validators.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmsSettings"]},r.prototype.updateValidators=function(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([i.Validators.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-send-sms-config",template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),xe=function(){function e(){}return e=b([t.NgModule({declarations:[x,T,q,S,I,k,N,V,E,A,L,X,ee,te,re,me,ue,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule,se],exports:[x,T,q,S,I,k,N,V,E,A,L,X,ee,te,re,me,ue,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe]})],e)}(),Te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.checkMessageConfigForm},r.prototype.onConfigurationSet=function(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})},r.prototype.validateConfig=function(){var e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0},r.prototype.removeMessageName=function(e){var t=this.checkMessageConfigForm.get("messageNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))},r.prototype.removeMetadataName=function(e){var t=this.checkMessageConfigForm.get("metadataNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))},r.prototype.addMessageName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("messageNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("messageNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.prototype.addMetadataName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("metadataNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("metadataNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-check-message-config",template:'
\n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),qe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.entitySearchDirection=Object.keys(a.EntitySearchDirection),n.entitySearchDirectionTranslationsMap=a.entitySearchDirectionTranslations,n}return y(r,e),r.prototype.configForm=function(){return this.checkRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],relationType:[e?e.relationType:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["checkForSingleEntity"]},r.prototype.updateValidators=function(e){var t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-check-relation-config",template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=R,n.rangeUnits=Object.keys(D),n.rangeUnitTranslationMap=B,n}return y(r,e),r.prototype.configForm=function(){return this.geoFilterConfigForm},r.prototype.onConfigurationSet=function(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterType").setValidators([]):this.geoFilterConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoFilterConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoFilterConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ie=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.messageTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-message-type-config",template:'
\n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allowedEntityTypes=[a.EntityType.DEVICE,a.EntityType.ASSET,a.EntityType.ENTITY_VIEW,a.EntityType.TENANT,a.EntityType.CUSTOMER,a.EntityType.USER,a.EntityType.DASHBOARD,a.EntityType.RULE_CHAIN,a.EntityType.RULE_NODE],n}return y(r,e),r.prototype.configForm=function(){return this.originatorTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-originator-type-config",template:'
\n \n \n \n
\n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ne=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-filter-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Ve=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.switchConfigForm},r.prototype.onConfigurationSet=function(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.switchConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-filter-node-switch-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Ee=function(e){function r(t,r,n){var o,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.fb=n,s.alarmStatusTranslationsMap=a.alarmStatusTranslations,s.alarmStatusList=[],s.searchText="",s.displayStatusFn=s.displayStatus.bind(s);try{for(var m=C(Object.keys(a.AlarmStatus)),u=m.next();!u.done;u=m.next()){var d=u.value;s.alarmStatusList.push(a.AlarmStatus[d])}}catch(e){o={error:e}}finally{try{u&&!u.done&&(l=m.return)&&l.call(m)}finally{if(o)throw o.error}}return s.statusFormControl=new i.FormControl(""),s.filteredAlarmStatus=s.statusFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return s.fetchAlarmStatus(e)})),f.share()),s}return y(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.alarmStatusConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[i.Validators.required]]})},r.prototype.displayStatus=function(e){return e?this.translate.instant(a.alarmStatusTranslations.get(e)):void 0},r.prototype.fetchAlarmStatus=function(e){var t=this,r=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){var n=this.searchText.toUpperCase();return c.of(r.filter((function(e){return t.translate.instant(a.alarmStatusTranslations.get(a.AlarmStatus[e])).toUpperCase().includes(n)})))}return c.of(r)},r.prototype.alarmStatusSelected=function(e){this.addAlarmStatus(e.option.value),this.clear("")},r.prototype.removeAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}},r.prototype.addAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))},r.prototype.getAlarmStatusList=function(){var e=this;return this.alarmStatusList.filter((function(t){return-1===e.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(t)}))},r.prototype.onAlarmStatusInputFocus=function(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.alarmStatusInput.nativeElement.blur(),t.alarmStatusInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},b([t.ViewChild("alarmStatusInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"alarmStatusInput",void 0),r=b([t.Component({selector:"tb-filter-node-check-alarm-status-config",template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n'}),h("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ae=function(){function e(){}return e=b([t.NgModule({declarations:[Te,qe,Se,Ie,ke,Ne,Ve,Ee],imports:[r.CommonModule,a.SharedModule,se],exports:[Te,qe,Se,Ie,ke,Ne,Ve,Ee]})],e)}(),Le=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.customerAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-customer-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Me=function(e){function r(t,r,n){var a,o,l=e.call(this,t)||this;l.store=t,l.translate=r,l.fb=n,l.entityDetailsTranslationsMap=H,l.entityDetailsList=[],l.searchText="",l.displayDetailsFn=l.displayDetails.bind(l);try{for(var s=C(Object.keys(K)),m=s.next();!m.done;m=s.next()){var u=m.value;l.entityDetailsList.push(K[u])}}catch(e){a={error:e}}finally{try{m&&!m.done&&(o=s.return)&&o.call(s)}finally{if(a)throw a.error}}return l.detailsFormControl=new i.FormControl(""),l.filteredEntityDetails=l.detailsFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return l.fetchEntityDetails(e)})),f.share()),l}return y(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.entityDetailsConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[i.Validators.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})},r.prototype.displayDetails=function(e){return e?this.translate.instant(H.get(e)):void 0},r.prototype.fetchEntityDetails=function(e){var t=this;if(this.searchText=e,this.searchText&&this.searchText.length){var r=this.searchText.toUpperCase();return c.of(this.entityDetailsList.filter((function(e){return t.translate.instant(H.get(K[e])).toUpperCase().includes(r)})))}return c.of(this.entityDetailsList)},r.prototype.detailsFieldSelected=function(e){this.addDetailsField(e.option.value),this.clear("")},r.prototype.removeDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}},r.prototype.addDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))},r.prototype.onEntityDetailsInputFocus=function(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.detailsInput.nativeElement.blur(),t.detailsInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},b([t.ViewChild("detailsInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"detailsInput",void 0),r=b([t.Component({selector:"tb-enrichment-node-entity-details-config",template:'
\n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-entity-details-matching\n
\n
\n
\n
\n
\n \n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
tb.rulenode.add-to-metadata-hint
\n
\n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}"]}),h("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.deviceAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[i.Validators.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.deviceAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.deviceAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.deviceAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.deviceAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-device-attributes-config",template:'
\n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),we=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.originatorAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.originatorAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.originatorAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.originatorAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.originatorAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-originator-attributes-config",template:'
\n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.originatorFieldsConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-originator-fields-config",template:'
\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),De=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n.fetchMode=G,n.fetchModes=Object.keys(G),n.samplingOrders=Object.keys(U),n.timeUnits=Object.keys(w),n.timeUnitsTranslationMap=O,n}return y(r,e),r.prototype.configForm=function(){return this.getTelemetryFromDatabaseConfigForm},r.prototype.onConfigurationSet=function(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],fetchMode:[e?e.fetchMode:null,[i.Validators.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchMode","useMetadataIntervalPatterns"]},r.prototype.updateValidators=function(e){var t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,r=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===G.ALL?(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([i.Validators.required,i.Validators.min(2),i.Validators.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),r?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([i.Validators.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})},r.prototype.removeKey=function(e,t){var r=this.getTelemetryFromDatabaseConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.getTelemetryFromDatabaseConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-get-telemetry-from-database",template:'
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
\n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
\n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-interval-patterns-hint
\n
\n
\n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.relatedAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[i.Validators.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-related-attributes-config",template:'
\n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.tenantAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-tenant-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.calculateDeltaConfigForm},r.prototype.onConfigurationSet=function(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e?e.inputValueKey:null,[i.Validators.required]],outputValueKey:[e?e.outputValueKey:null,[i.Validators.required]],useCache:[e?e.useCache:null,[]],addPeriodBetweenMsgs:[!!e&&e.addPeriodBetweenMsgs,[]],periodValueKey:[e?e.periodValueKey:null,[]],round:[e?e.round:null,[i.Validators.min(0),i.Validators.max(15)]],tellFailureIfInputValueKeyIsAbsent:[e?e.tellFailureIfInputValueKeyIsAbsent:null,[]],tellFailureIfDeltaIsNegative:[e?e.tellFailureIfDeltaIsNegative:null,[]]})},r.prototype.updateValidators=function(e){console.log("updateValidators"),this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?(console.log("true"),this.calculateDeltaConfigForm.get("periodValueKey").setValidators([i.Validators.required])):(console.log("false"),this.calculateDeltaConfigForm.get("periodValueKey").setValidators([])),this.calculateDeltaConfigForm.get("inputValueKey").updateValueAndValidity({emitEvent:e}),this.calculateDeltaConfigForm.get("outputValueKey").updateValueAndValidity({emitEvent:e}),this.calculateDeltaConfigForm.get("round").updateValueAndValidity({emitEvent:e}),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})},r.prototype.validatorTriggers=function(){return["addPeriodBetweenMsgs"]},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-calculate-delta-config",template:'
\n
\n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-input-value-key-is-absent\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ge=function(){function e(){}return e=b([t.NgModule({declarations:[Le,Me,Pe,we,Re,De,Oe,Ke,Be],imports:[r.CommonModule,a.SharedModule,se],exports:[Le,Me,Pe,we,Re,De,Oe,Ke,Be]})],e)}(),Ue=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.originatorSource=v,n.originatorSources=Object.keys(v),n.originatorSourceTranslationMap=P,n}return y(r,e),r.prototype.configForm=function(){return this.changeOriginatorConfigForm},r.prototype.onConfigurationSet=function(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[i.Validators.required]],relationsQuery:[e?e.relationsQuery:null,[]]})},r.prototype.validatorTriggers=function(){return["originatorSource"]},r.prototype.updateValidators=function(e){var t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===v.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([i.Validators.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-transformation-node-change-originator-config",template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),je=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-transformation-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),He=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.toEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[i.Validators.required]],toTemplate:[e?e.toTemplate:null,[i.Validators.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[i.Validators.required]],bodyTemplate:[e?e.bodyTemplate:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-transformation-node-to-email-config",template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ze=function(){function e(){}return e=b([t.NgModule({declarations:[Ue,je,He],imports:[r.CommonModule,a.SharedModule,se],exports:[Ue,je,He]})],e)}(),$e=function(){function e(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-name-pattern-hint":"Name pattern, use ${metaKeyName} to substitute variables from metadata","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-type-pattern-hint":"Type pattern, use ${metaKeyName} to substitute variables from metadata","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-name-pattern-hint":"Customer name pattern, use ${metaKeyName} to substitute variables from metadata","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","client-attributes-hint":"Client attributes, use ${metaKeyName} to substitute variables from metadata","shared-attributes":"Shared attributes","shared-attributes-hint":"Shared attributes, use ${metaKeyName} to substitute variables from metadata","server-attributes":"Server attributes","server-attributes-hint":"Server attributes, use ${metaKeyName} to substitute variables from metadata","notify-device":"Notify Device","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","latest-timeseries":"Latest timeseries","latest-timeseries-hint":"Latest timeseries, use ${metaKeyName} to substitute variables from metadata","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-hint":"Relation type pattern, use ${metaKeyName} to substitute variables from metadata","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use metadata period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds metadata pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","period-in-seconds-pattern-hint":"Period in seconds pattern, use ${metaKeyName} to substitute variables from metadata","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","from-template-hint":"From address template, use ${metaKeyName} to substitute variables from metadata","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":"Comma separated address list, use ${metaKeyName} to substitute variables from metadata","cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","subject-template-hint":"Mail subject template, use ${metaKeyName} to substitute variables from metadata","body-template":"Body Template","body-template-required":"Body Template is required","body-template-hint":"Mail body template, use ${metaKeyName} to substitute variables from metadata","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","endpoint-url-pattern-hint":"HTTP URL address pattern, use ${metaKeyName} to substitute variables from metadata","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":"Use ${metaKeyName} in header/value fields to substitute variables from metadata",header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required","mqtt-topic-pattern-hint":"MQTT topic pattern, use ${metaKeyName} to substitute variables from metadata",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","topic-arn-pattern-hint":"Topic ARN pattern, use ${metaKeyName} to substitute variables from metadata","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","queue-url-pattern-hint":"Queue URL pattern, use ${metaKeyName} to substitute variables from metadata","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":"Use ${metaKeyName} in name/value fields to substitute variables from metadata","connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file *","private-key":"Client private key file *",cert:"Client certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use metadata interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","start-interval-pattern-hint":"Start interval pattern, use ${metaKeyName} to substitute variables from metadata","end-interval-pattern-hint":"End interval pattern, use ${metaKeyName} to substitute variables from metadata","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":"Comma separated Phone Numbers, use ${metaKeyName} to substitute variables from metadata","sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","sms-message-template-hint":"SMS message template, use ${metaKeyName} to substitute variables from metadata","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-zip":"Zip","entity-details-address":"Address","entity-details-address2":"Address2","entity-details-additional_info":"Additional Info","entity-details-phone":"Phone","entity-details-email":"Email","add-to-metadata":"Add selected details to message metadata","add-to-metadata-hint":"If selected, adds the selected details keys to the message metadata instead of message data.","entity-details-list-empty":"No entity details selected.","no-entity-details-matching":"No entity details matching were found.","custom-table-name":"Custom table name","custom-table-name-required":"Table Name is required","custom-table-hint":"You should enter the table name without prefix 'cs_tb_'.","message-field":"Message field","message-field-required":"Message field is required.","table-col":"Table column","table-col-required":"Table column is required.","latitude-key-name":"Latitude key name","longitude-key-name":"Longitude key name","latitude-key-name-required":"Latitude key name is required.","longitude-key-name-required":"Longitude key name is required.","fetch-perimeter-info-from-message-metadata":"Fetch perimeter information from message metadata","perimeter-circle":"Circle","perimeter-polygon":"Polygon","perimeter-type":"Perimeter type","circle-center-latitude":"Center latitude","circle-center-latitude-required":"Center latitude is required.","circle-center-longitude":"Center longitude","circle-center-longitude-required":"Center longitude is required.","range-unit-meter":"Meter","range-unit-kilometer":"Kilometer","range-unit-foot":"Foot","range-unit-mile":"Mile","range-unit-nautical-mile":"Nautical mile","range-units":"Range units",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].","min-inside-duration":"Minimal inside duration","min-inside-duration-value-required":"Minimal inside duration is required","min-inside-duration-time-unit":"Minimal inside duration time unit","min-outside-duration":"Minimal outside duration","min-outside-duration-value-required":"Minimal outside duration is required","min-outside-duration-time-unit":"Minimal outside duration time unit","tell-failure-if-absent":"Tell Failure","tell-failure-if-absent-hint":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"get-latest-value-with-ts":"Fetch Latest telemetry with Timestamp","get-latest-value-with-ts-hint":'If selected, latest telemetry values will be added to the outbound message metadata with timestamp, e.g: "temp": "{\\"ts\\":1574329385897,\\"value\\":42}"',"use-redis-queue":"Use redis queue for message persistence","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required.","output-value-key":"Output value key","output-value-key-required":"Output value key is required.",round:"Decimals","round-range":"Decimals should be in a range from 0 to 15.","use-cache":"Use cache for latest value","tell-failure-if-input-value-key-is-absent":"Tell Failure if input value key is absent","tell-failure-if-delta-is-negative":"Tell Failure if delta is negative","add-period-between-msgs":"Add period between messages","period-value-key":"Period value key","period-key-required":"Period value key is required."},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"}}},!0)}(e)}return e.ctorParameters=function(){return[{type:n.TranslateService}]},e=b([t.NgModule({declarations:[F],imports:[r.CommonModule,a.SharedModule],exports:[xe,Ae,Ge,ze,F]}),h("design:paramtypes",[n.TranslateService])],e)}();e.RuleNodeCoreConfigModule=$e,e.ɵa=F,e.ɵb=xe,e.ɵba=he,e.ɵbb=Ce,e.ɵbc=ve,e.ɵbd=Fe,e.ɵbe=se,e.ɵbf=ne,e.ɵbg=ae,e.ɵbh=oe,e.ɵbi=ie,e.ɵbj=le,e.ɵbk=Ae,e.ɵbl=Te,e.ɵbm=qe,e.ɵbn=Se,e.ɵbo=Ie,e.ɵbp=ke,e.ɵbq=Ne,e.ɵbr=Ve,e.ɵbs=Ee,e.ɵbt=Ge,e.ɵbu=Le,e.ɵbv=Me,e.ɵbw=Pe,e.ɵbx=we,e.ɵby=Re,e.ɵbz=De,e.ɵc=x,e.ɵca=Oe,e.ɵcb=Ke,e.ɵcc=Be,e.ɵcd=ze,e.ɵce=Ue,e.ɵcf=je,e.ɵcg=He,e.ɵd=T,e.ɵe=q,e.ɵf=S,e.ɵg=I,e.ɵh=k,e.ɵi=N,e.ɵj=V,e.ɵk=E,e.ɵl=A,e.ɵm=L,e.ɵn=X,e.ɵo=ee,e.ɵp=te,e.ɵq=re,e.ɵr=me,e.ɵs=ue,e.ɵt=de,e.ɵu=pe,e.ɵv=ce,e.ɵw=fe,e.ɵx=ge,e.ɵy=ye,e.ɵz=be,Object.defineProperty(e,"__esModule",{value:!0})})); + ***************************************************************************** */var g=function(e,t){return(g=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])})(e,t)};function y(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}g(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}function b(e,t,r,n){var a,o=arguments.length,i=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,r,n);else for(var l=e.length-1;l>=0;l--)(a=e[l])&&(i=(o<3?a(i):o>3?a(t,r,i):a(t,r))||i);return o>3&&i&&Object.defineProperty(t,r,i),i}function h(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}Object.create;function C(e){var t="function"==typeof Symbol&&Symbol.iterator,r=t&&e[t],n=0;if(r)return r.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}Object.create;var v,F=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.emptyConfigForm},r.prototype.onConfigurationSet=function(e){this.emptyConfigForm=this.fb.group({})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-node-empty-config",template:"
"}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),x=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return y(r,e),r.prototype.configForm=function(){return this.attributesConfigForm},r.prototype.onConfigurationSet=function(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]],notifyDevice:[!e||e.scope,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-attributes-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),T=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.timeseriesConfigForm},r.prototype.onConfigurationSet=function(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-timeseries-config",template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),q=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.rpcRequestConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rpc-request-config",template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),S=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.logConfigForm},r.prototype.onConfigurationSet=function(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.logConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-log-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),I=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.assignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),k=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.clearAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],alarmType:[e?e.alarmType:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-clear-alarm-config",template:'
\n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),N=function(e){function r(t,r,n,o){var i=e.call(this,t)||this;return i.store=t,i.fb=r,i.nodeScriptTestService=n,i.translate=o,i.alarmSeverities=Object.keys(a.AlarmSeverity),i.alarmSeverityTranslationMap=a.alarmSeverityTranslations,i.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],i}return y(r,e),r.prototype.configForm=function(){return this.createAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]]})},r.prototype.validatorTriggers=function(){return["useMessageAlarmData"]},r.prototype.updateValidators=function(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([i.Validators.required]),this.createAlarmConfigForm.get("severity").setValidators([i.Validators.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})},r.prototype.testScript=function(){var e=this,t=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.removeKey=function(e,t){var r=this.createAlarmConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.createAlarmConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.createAlarmConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.createAlarmConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-create-alarm-config",template:'
\n \n \n \n
\n \n
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n \n \n
\n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),V=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return y(r,e),r.prototype.configForm=function(){return this.createRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[i.Validators.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["entityType"]},r.prototype.updateValidators=function(e){var t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==a.EntityType.DEVICE&&t!==a.EntityType.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([i.Validators.required]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-create-relation-config",template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),E=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.msgDelayConfigForm},r.prototype.onConfigurationSet=function(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(1e5)]]})},r.prototype.validatorTriggers=function(){return["useMetadataPeriodInSecondsPatterns"]},r.prototype.updateValidators=function(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([i.Validators.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([i.Validators.required,i.Validators.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-msg-delay-config",template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),A=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return y(r,e),r.prototype.configForm=function(){return this.deleteRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["deleteForSingleEntity","entityType"]},r.prototype.updateValidators=function(e){var t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,r=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&r?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-delete-relation-config",template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),L=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.generatorConfigForm},r.prototype.onConfigurationSet=function(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[i.Validators.required,i.Validators.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[i.Validators.required,i.Validators.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.prepareInputConfig=function(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e},r.prototype.prepareOutputConfig=function(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e},r.prototype.testScript=function(){var e=this,t=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId).subscribe((function(t){t&&e.generatorConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-generator-config",template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent);!function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(v||(v={}));var M,P=new Map([[v.CUSTOMER,"tb.rulenode.originator-customer"],[v.TENANT,"tb.rulenode.originator-tenant"],[v.RELATED,"tb.rulenode.originator-related"],[v.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(M||(M={}));var w,R=new Map([[M.CIRCLE,"tb.rulenode.perimeter-circle"],[M.POLYGON,"tb.rulenode.perimeter-polygon"]]);!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(w||(w={}));var D,O=new Map([[w.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[w.SECONDS,"tb.rulenode.time-unit-seconds"],[w.MINUTES,"tb.rulenode.time-unit-minutes"],[w.HOURS,"tb.rulenode.time-unit-hours"],[w.DAYS,"tb.rulenode.time-unit-days"]]);!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(D||(D={}));var K,B=new Map([[D.METER,"tb.rulenode.range-unit-meter"],[D.KILOMETER,"tb.rulenode.range-unit-kilometer"],[D.FOOT,"tb.rulenode.range-unit-foot"],[D.MILE,"tb.rulenode.range-unit-mile"],[D.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(K||(K={}));var G,U,j,H=new Map([[K.TITLE,"tb.rulenode.entity-details-title"],[K.COUNTRY,"tb.rulenode.entity-details-country"],[K.STATE,"tb.rulenode.entity-details-state"],[K.ZIP,"tb.rulenode.entity-details-zip"],[K.ADDRESS,"tb.rulenode.entity-details-address"],[K.ADDRESS2,"tb.rulenode.entity-details-address2"],[K.PHONE,"tb.rulenode.entity-details-phone"],[K.EMAIL,"tb.rulenode.entity-details-email"],[K.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(G||(G={})),function(e){e.ASC="ASC",e.DESC="DESC"}(U||(U={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(j||(j={}));var z,$=new Map([[j.STANDARD,"tb.rulenode.sqs-queue-standard"],[j.FIFO,"tb.rulenode.sqs-queue-fifo"]]),Q=["anonymous","basic","cert.PEM"],_=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),W=["sas","cert.PEM"],J=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(z||(z={}));var Y=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],Z=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]),X=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=R,n.rangeUnits=Object.keys(D),n.rangeUnitTranslationMap=B,n.timeUnits=Object.keys(w),n.timeUnitsTranslationMap=O,n}return y(r,e),r.prototype.configForm=function(){return this.geoActionConfigForm},r.prototype.onConfigurationSet=function(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[i.Validators.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterType").setValidators([]):this.geoActionConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoActionConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoActionConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.msgCountConfigForm},r.prototype.onConfigurationSet=function(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[i.Validators.required,i.Validators.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-msg-count-config",template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.rpcReplyConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rpc-reply-config",template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.saveToCustomTableConfigForm},r.prototype.onConfigurationSet=function(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[i.Validators.required]],fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-custom-table-config",template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n \n \n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ne=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.translate=r,o.injector=n,o.fb=a,o.propagateChange=null,o.valueChangeSubscription=null,o}var a;return y(r,e),a=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){this.ngControl=this.injector.get(i.NgControl),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))},r.prototype.keyValsFormArray=function(){return this.kvListFormGroup.get("keyVals")},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t,r,n=this;this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();var a=[];if(e)try{for(var o=C(Object.keys(e)),l=o.next();!l.done;l=o.next()){var s=l.value;Object.prototype.hasOwnProperty.call(e,s)&&a.push(this.fb.group({key:[s,[i.Validators.required]],value:[e[s],[i.Validators.required]]}))}}catch(e){t={error:e}}finally{try{l&&!l.done&&(r=o.return)&&r.call(o)}finally{if(t)throw t.error}}this.kvListFormGroup.setControl("keyVals",this.fb.array(a)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((function(){n.updateModel()}))},r.prototype.removeKeyVal=function(e){this.kvListFormGroup.get("keyVals").removeAt(e)},r.prototype.addKeyVal=function(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[i.Validators.required]],value:["",[i.Validators.required]]}))},r.prototype.validate=function(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}},r.prototype.updateModel=function(){var e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{var t={};e.forEach((function(e){t[e.key]=e.value})),this.propagateChange(t)}},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:t.Injector},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",String)],r.prototype,"requiredText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"keyText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"keyRequiredText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"valText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"valRequiredText",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=a=b([t.Component({selector:"tb-kv-map-config",template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n \n
\n \n
\n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return a})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return a})),multi:!0}],styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:rgba(0,0,0,.54);font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}"]}),h("design:paramtypes",[o.Store,n.TranslateService,t.Injector,i.FormBuilder])],r)}(a.PageComponent),ae=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n.propagateChange=null,n}var n;return y(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[i.Validators.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((function(t){e.deviceRelationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=b([t.Component({selector:"tb-device-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-type
\n \n \n
device.device-types
\n \n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.propagateChange=null,n}var n;return y(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((function(t){e.relationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=b([t.Component({selector:"tb-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),ie=function(e){function r(t,r,n,o){var i,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.truncate=n,s.fb=o,s.placeholder="tb.rulenode.message-type",s.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],s.messageTypes=[],s.messageTypesList=[],s.searchText="",s.propagateChange=function(e){},s.messageTypeConfigForm=s.fb.group({messageType:[null]});try{for(var u=C(Object.keys(a.MessageType)),d=u.next();!d.done;d=u.next()){var p=d.value;s.messageTypesList.push({name:a.messageTypeNames.get(a.MessageType[p]),value:p})}}catch(e){i={error:e}}finally{try{d&&!d.done&&(l=u.return)&&l.call(u)}finally{if(i)throw i.error}}return s}var l;return y(r,e),l=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.ngOnInit=function(){var e=this;this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(t){return e.fetchMessageTypes(t)})),f.share())},r.prototype.ngAfterViewInit=function(){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t=this;this.searchText="",this.messageTypes.length=0,e&&e.forEach((function(e){var r=t.messageTypesList.find((function(t){return t.value===e}));r?t.messageTypes.push({name:r.name,value:r.value}):t.messageTypes.push({name:e,value:e})}))},r.prototype.displayMessageTypeFn=function(e){return e?e.name:void 0},r.prototype.textIsNotEmpty=function(e){return!!(e&&null!=e&&e.length>0)},r.prototype.createMessageType=function(e,t){e.preventDefault(),this.transformMessageType(t)},r.prototype.add=function(e){this.transformMessageType(e.value)},r.prototype.fetchMessageTypes=function(e){if(this.searchText=e,this.searchText&&this.searchText.length){var t=this.searchText.toUpperCase();return c.of(this.messageTypesList.filter((function(e){return e.name.toUpperCase().includes(t)})))}return c.of(this.messageTypesList)},r.prototype.transformMessageType=function(e){if((e||"").trim()){var t=null,r=e.trim(),n=this.messageTypesList.find((function(e){return e.name===r}));(t=n?{name:n.name,value:n.value}:{name:r,value:r})&&this.addMessageType(t)}this.clear("")},r.prototype.remove=function(e){var t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())},r.prototype.selected=function(e){this.addMessageType(e.option.value),this.clear("")},r.prototype.addMessageType=function(e){-1===this.messageTypes.findIndex((function(t){return t.value===e.value}))&&(this.messageTypes.push(e),this.updateModel())},r.prototype.onFocus=function(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((function(){t.messageTypeInput.nativeElement.blur(),t.messageTypeInput.nativeElement.focus()}),0)},r.prototype.updateModel=function(){var e=this.messageTypes.map((function(e){return e.value}));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:a.TruncatePipe},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),b([t.Input(),h("design:type",String)],r.prototype,"label",void 0),b([t.Input(),h("design:type",Object)],r.prototype,"placeholder",void 0),b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.ViewChild("chipList",{static:!1}),h("design:type",d.MatChipList)],r.prototype,"chipList",void 0),b([t.ViewChild("messageTypeAutocomplete",{static:!1}),h("design:type",p.MatAutocomplete)],r.prototype,"matAutocomplete",void 0),b([t.ViewChild("messageTypeInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"messageTypeInput",void 0),r=l=b([t.Component({selector:"tb-message-types-config",template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return l})),multi:!0}]}),h("design:paramtypes",[o.Store,n.TranslateService,a.TruncatePipe,i.FormBuilder])],r)}(a.PageComponent),le=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.subscriptions=[],n.disableCertPemCredentials=!1,n.allCredentialsTypes=Q,n.credentialsTypeTranslationsMap=_,n.propagateChange=null,n}var n;return y(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.credentialsConfigFormGroup=this.fb.group({type:[null,[i.Validators.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(f.distinctUntilChanged()).subscribe((function(){e.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((function(){e.credentialsTypeChanged()})))},r.prototype.ngOnChanges=function(e){var t,r,n=this;try{for(var a=C(Object.keys(e)),o=a.next();!o.done;o=a.next()){var i=o.value,l=e[i];if(!l.firstChange&&l.currentValue!==l.previousValue)if(l.currentValue&&"disableCertPemCredentials"===i)"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((function(){n.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}catch(e){t={error:e}}finally{try{o&&!o.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}},r.prototype.ngOnDestroy=function(){this.subscriptions.forEach((function(e){return e.unsubscribe()}))},r.prototype.writeValue=function(e){s.isDefinedAndNotNull(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))},r.prototype.setDisabledState=function(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())},r.prototype.updateView=function(){var e=this.credentialsConfigFormGroup.value,t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.validate=function(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}},r.prototype.credentialsTypeChanged=function(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()},r.prototype.updateValidators=function(e){void 0===e&&(e=!1);var t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([i.Validators.required]),this.credentialsConfigFormGroup.get("password").setValidators([i.Validators.required]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(i.Validators.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})},r.prototype.requiredFilesSelected=function(e,t){return void 0===t&&(t=null),function(r){return t||(t=[Object.keys(r.controls)]),(null==r?void 0:r.controls)&&t.some((function(t){return t.every((function(t){return!e(r.controls[t])}))}))?null:{notAllRequiredFilesSelected:!0}}},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),b([t.Input(),h("design:type",Object)],r.prototype,"disableCertPemCredentials",void 0),r=n=b([t.Component({selector:"tb-credentials-config",template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n
\n
\n
\n
\n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),se=function(){function e(){}return e=b([t.NgModule({declarations:[ne,ae,oe,ie,le],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule],exports:[ne,ae,oe,ie,le]})],e)}(),me=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.unassignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-un-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ue=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.snsConfigForm},r.prototype.onConfigurationSet=function(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[i.Validators.required]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-sns-config",template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),de=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.sqsQueueType=j,n.sqsQueueTypes=Object.keys(j),n.sqsQueueTypeTranslationsMap=$,n}return y(r,e),r.prototype.configForm=function(){return this.sqsConfigForm},r.prototype.onConfigurationSet=function(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[i.Validators.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[i.Validators.required]],delaySeconds:[e?e.delaySeconds:null,[i.Validators.min(0),i.Validators.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-sqs-config",template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.pubSubConfigForm},r.prototype.onConfigurationSet=function(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[i.Validators.required]],topicName:[e?e.topicName:null,[i.Validators.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[i.Validators.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[i.Validators.required]],messageAttributes:[e?e.messageAttributes:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-pub-sub-config",template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.ackValues=["all","-1","0","1"],n.ToByteStandartCharsetTypesValues=Y,n.ToByteStandartCharsetTypeTranslationMap=Z,n}return y(r,e),r.prototype.configForm=function(){return this.kafkaConfigForm},r.prototype.onConfigurationSet=function(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],bootstrapServers:[e?e.bootstrapServers:null,[i.Validators.required]],retries:[e?e.retries:null,[i.Validators.min(0)]],batchSize:[e?e.batchSize:null,[i.Validators.min(0)]],linger:[e?e.linger:null,[i.Validators.min(0)]],bufferMemory:[e?e.bufferMemory:null,[i.Validators.min(0)]],acks:[e?e.acks:null,[i.Validators.required]],keySerializer:[e?e.keySerializer:null,[i.Validators.required]],valueSerializer:[e?e.valueSerializer:null,[i.Validators.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})},r.prototype.validatorTriggers=function(){return["addMetadataKeyValuesAsKafkaHeaders"]},r.prototype.updateValidators=function(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([i.Validators.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-kafka-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.mqttConfigForm},r.prototype.onConfigurationSet=function(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-mqtt-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n \n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],n}return y(r,e),r.prototype.configForm=function(){return this.rabbitMqConfigForm},r.prototype.onConfigurationSet=function(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[i.Validators.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[i.Validators.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rabbit-mq-config",template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ye=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.proxySchemes=["http","https"],n.httpRequestTypes=Object.keys(z),n}return y(r,e),r.prototype.configForm=function(){return this.restApiCallConfigForm},r.prototype.onConfigurationSet=function(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[i.Validators.required]],requestMethod:[e?e.requestMethod:null,[i.Validators.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[i.Validators.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})},r.prototype.validatorTriggers=function(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]},r.prototype.updateValidators=function(e){var t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,r=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,n=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;n&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(n?[i.Validators.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(n?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([i.Validators.min(0)])),r?this.restApiCallConfigForm.get("maxQueueSize").setValidators([i.Validators.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rest-api-call-config",template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n \n \n \n tb.rulenode.max-parallel-requests-count\n \n \n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.smtpProtocols=["smtp","smtps"],n.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"],n}return y(r,e),r.prototype.configForm=function(){return this.sendEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmtpSettings","enableProxy"]},r.prototype.updateValidators=function(e){var t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,r=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([i.Validators.required,i.Validators.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(r?[i.Validators.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(r?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-send-email-config",template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),he=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.serviceType=a.ServiceType.TB_RULE_ENGINE,n}return y(r,e),r.prototype.configForm=function(){return this.checkPointConfigForm},r.prototype.onConfigurationSet=function(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-check-point-config",template:'
\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allAzureIotHubCredentialsTypes=W,n.azureIotHubCredentialsTypeTranslationsMap=J,n}return y(r,e),r.prototype.configForm=function(){return this.azureIotHubConfigForm},r.prototype.onConfigurationSet=function(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[i.Validators.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[i.Validators.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})},r.prototype.prepareOutputConfig=function(e){var t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e},r.prototype.validatorTriggers=function(){return["credentials.type"]},r.prototype.updateValidators=function(e){var t=this.azureIotHubConfigForm.get("credentials"),r=t.get("type").value;switch(e&&t.reset({type:r},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),r){case"sas":t.get("sasKey").setValidators([i.Validators.required]);break;case"cert.PEM":t.get("privateKey").setValidators([i.Validators.required]),t.get("privateKeyFileName").setValidators([i.Validators.required]),t.get("cert").setValidators([i.Validators.required]),t.get("certFileName").setValidators([i.Validators.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-azure-iot-hub-config",template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.deviceProfile},r.prototype.onConfigurationSet=function(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,i.Validators.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,i.Validators.required]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-device-profile-config",template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.sendSmsConfigForm},r.prototype.onConfigurationSet=function(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[i.Validators.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[i.Validators.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmsSettings"]},r.prototype.updateValidators=function(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([i.Validators.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-send-sms-config",template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),xe=function(){function e(){}return e=b([t.NgModule({declarations:[x,T,q,S,I,k,N,V,E,A,L,X,ee,te,re,me,ue,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule,se],exports:[x,T,q,S,I,k,N,V,E,A,L,X,ee,te,re,me,ue,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe]})],e)}(),Te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.checkMessageConfigForm},r.prototype.onConfigurationSet=function(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})},r.prototype.validateConfig=function(){var e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0},r.prototype.removeMessageName=function(e){var t=this.checkMessageConfigForm.get("messageNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))},r.prototype.removeMetadataName=function(e){var t=this.checkMessageConfigForm.get("metadataNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))},r.prototype.addMessageName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("messageNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("messageNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.prototype.addMetadataName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("metadataNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("metadataNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-check-message-config",template:'
\n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),qe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.entitySearchDirection=Object.keys(a.EntitySearchDirection),n.entitySearchDirectionTranslationsMap=a.entitySearchDirectionTranslations,n}return y(r,e),r.prototype.configForm=function(){return this.checkRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],relationType:[e?e.relationType:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["checkForSingleEntity"]},r.prototype.updateValidators=function(e){var t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-check-relation-config",template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=R,n.rangeUnits=Object.keys(D),n.rangeUnitTranslationMap=B,n}return y(r,e),r.prototype.configForm=function(){return this.geoFilterConfigForm},r.prototype.onConfigurationSet=function(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterType").setValidators([]):this.geoFilterConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoFilterConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoFilterConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ie=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.messageTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-message-type-config",template:'
\n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allowedEntityTypes=[a.EntityType.DEVICE,a.EntityType.ASSET,a.EntityType.ENTITY_VIEW,a.EntityType.TENANT,a.EntityType.CUSTOMER,a.EntityType.USER,a.EntityType.DASHBOARD,a.EntityType.RULE_CHAIN,a.EntityType.RULE_NODE],n}return y(r,e),r.prototype.configForm=function(){return this.originatorTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-originator-type-config",template:'
\n \n \n \n
\n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ne=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-filter-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Ve=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.switchConfigForm},r.prototype.onConfigurationSet=function(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.switchConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-filter-node-switch-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Ee=function(e){function r(t,r,n){var o,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.fb=n,s.alarmStatusTranslationsMap=a.alarmStatusTranslations,s.alarmStatusList=[],s.searchText="",s.displayStatusFn=s.displayStatus.bind(s);try{for(var m=C(Object.keys(a.AlarmStatus)),u=m.next();!u.done;u=m.next()){var d=u.value;s.alarmStatusList.push(a.AlarmStatus[d])}}catch(e){o={error:e}}finally{try{u&&!u.done&&(l=m.return)&&l.call(m)}finally{if(o)throw o.error}}return s.statusFormControl=new i.FormControl(""),s.filteredAlarmStatus=s.statusFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return s.fetchAlarmStatus(e)})),f.share()),s}return y(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.alarmStatusConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[i.Validators.required]]})},r.prototype.displayStatus=function(e){return e?this.translate.instant(a.alarmStatusTranslations.get(e)):void 0},r.prototype.fetchAlarmStatus=function(e){var t=this,r=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){var n=this.searchText.toUpperCase();return c.of(r.filter((function(e){return t.translate.instant(a.alarmStatusTranslations.get(a.AlarmStatus[e])).toUpperCase().includes(n)})))}return c.of(r)},r.prototype.alarmStatusSelected=function(e){this.addAlarmStatus(e.option.value),this.clear("")},r.prototype.removeAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}},r.prototype.addAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))},r.prototype.getAlarmStatusList=function(){var e=this;return this.alarmStatusList.filter((function(t){return-1===e.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(t)}))},r.prototype.onAlarmStatusInputFocus=function(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.alarmStatusInput.nativeElement.blur(),t.alarmStatusInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},b([t.ViewChild("alarmStatusInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"alarmStatusInput",void 0),r=b([t.Component({selector:"tb-filter-node-check-alarm-status-config",template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n'}),h("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ae=function(){function e(){}return e=b([t.NgModule({declarations:[Te,qe,Se,Ie,ke,Ne,Ve,Ee],imports:[r.CommonModule,a.SharedModule,se],exports:[Te,qe,Se,Ie,ke,Ne,Ve,Ee]})],e)}(),Le=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.customerAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-customer-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Me=function(e){function r(t,r,n){var a,o,l=e.call(this,t)||this;l.store=t,l.translate=r,l.fb=n,l.entityDetailsTranslationsMap=H,l.entityDetailsList=[],l.searchText="",l.displayDetailsFn=l.displayDetails.bind(l);try{for(var s=C(Object.keys(K)),m=s.next();!m.done;m=s.next()){var u=m.value;l.entityDetailsList.push(K[u])}}catch(e){a={error:e}}finally{try{m&&!m.done&&(o=s.return)&&o.call(s)}finally{if(a)throw a.error}}return l.detailsFormControl=new i.FormControl(""),l.filteredEntityDetails=l.detailsFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return l.fetchEntityDetails(e)})),f.share()),l}return y(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.entityDetailsConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[i.Validators.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})},r.prototype.displayDetails=function(e){return e?this.translate.instant(H.get(e)):void 0},r.prototype.fetchEntityDetails=function(e){var t=this;if(this.searchText=e,this.searchText&&this.searchText.length){var r=this.searchText.toUpperCase();return c.of(this.entityDetailsList.filter((function(e){return t.translate.instant(H.get(K[e])).toUpperCase().includes(r)})))}return c.of(this.entityDetailsList)},r.prototype.detailsFieldSelected=function(e){this.addDetailsField(e.option.value),this.clear("")},r.prototype.removeDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}},r.prototype.addDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))},r.prototype.onEntityDetailsInputFocus=function(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.detailsInput.nativeElement.blur(),t.detailsInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},b([t.ViewChild("detailsInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"detailsInput",void 0),r=b([t.Component({selector:"tb-enrichment-node-entity-details-config",template:'
\n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-entity-details-matching\n
\n
\n
\n
\n
\n \n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
tb.rulenode.add-to-metadata-hint
\n
\n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}"]}),h("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.deviceAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[i.Validators.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.deviceAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.deviceAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.deviceAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.deviceAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-device-attributes-config",template:'
\n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),we=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.originatorAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.originatorAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.originatorAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.originatorAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.originatorAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-originator-attributes-config",template:'
\n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.originatorFieldsConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-originator-fields-config",template:'
\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),De=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n.fetchMode=G,n.fetchModes=Object.keys(G),n.samplingOrders=Object.keys(U),n.timeUnits=Object.keys(w),n.timeUnitsTranslationMap=O,n}return y(r,e),r.prototype.configForm=function(){return this.getTelemetryFromDatabaseConfigForm},r.prototype.onConfigurationSet=function(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],fetchMode:[e?e.fetchMode:null,[i.Validators.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchMode","useMetadataIntervalPatterns"]},r.prototype.updateValidators=function(e){var t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,r=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===G.ALL?(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([i.Validators.required,i.Validators.min(2),i.Validators.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),r?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([i.Validators.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})},r.prototype.removeKey=function(e,t){var r=this.getTelemetryFromDatabaseConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.getTelemetryFromDatabaseConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-get-telemetry-from-database",template:'
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
\n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
\n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-interval-patterns-hint
\n
\n
\n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.relatedAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[i.Validators.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-related-attributes-config",template:'
\n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.tenantAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-tenant-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.calculateDeltaConfigForm},r.prototype.onConfigurationSet=function(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e?e.inputValueKey:null,[i.Validators.required]],outputValueKey:[e?e.outputValueKey:null,[i.Validators.required]],useCache:[e?e.useCache:null,[]],addPeriodBetweenMsgs:[!!e&&e.addPeriodBetweenMsgs,[]],periodValueKey:[e?e.periodValueKey:null,[]],round:[e?e.round:null,[i.Validators.min(0),i.Validators.max(15)]],tellFailureIfInputValueKeyIsAbsent:[e?e.tellFailureIfInputValueKeyIsAbsent:null,[]],tellFailureIfDeltaIsNegative:[e?e.tellFailureIfDeltaIsNegative:null,[]]})},r.prototype.updateValidators=function(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([i.Validators.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("inputValueKey").updateValueAndValidity({emitEvent:e}),this.calculateDeltaConfigForm.get("outputValueKey").updateValueAndValidity({emitEvent:e}),this.calculateDeltaConfigForm.get("round").updateValueAndValidity({emitEvent:e}),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})},r.prototype.validatorTriggers=function(){return["addPeriodBetweenMsgs"]},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-calculate-delta-config",template:'
\n
\n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-input-value-key-is-absent\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ge=function(){function e(){}return e=b([t.NgModule({declarations:[Le,Me,Pe,we,Re,De,Oe,Ke,Be],imports:[r.CommonModule,a.SharedModule,se],exports:[Le,Me,Pe,we,Re,De,Oe,Ke,Be]})],e)}(),Ue=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.originatorSource=v,n.originatorSources=Object.keys(v),n.originatorSourceTranslationMap=P,n}return y(r,e),r.prototype.configForm=function(){return this.changeOriginatorConfigForm},r.prototype.onConfigurationSet=function(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[i.Validators.required]],relationsQuery:[e?e.relationsQuery:null,[]]})},r.prototype.validatorTriggers=function(){return["originatorSource"]},r.prototype.updateValidators=function(e){var t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===v.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([i.Validators.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-transformation-node-change-originator-config",template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),je=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-transformation-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),He=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.toEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[i.Validators.required]],toTemplate:[e?e.toTemplate:null,[i.Validators.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[i.Validators.required]],bodyTemplate:[e?e.bodyTemplate:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-transformation-node-to-email-config",template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ze=function(){function e(){}return e=b([t.NgModule({declarations:[Ue,je,He],imports:[r.CommonModule,a.SharedModule,se],exports:[Ue,je,He]})],e)}(),$e=function(){function e(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-name-pattern-hint":"Name pattern, use ${metaKeyName} to substitute variables from metadata","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-type-pattern-hint":"Type pattern, use ${metaKeyName} to substitute variables from metadata","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-name-pattern-hint":"Customer name pattern, use ${metaKeyName} to substitute variables from metadata","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","client-attributes-hint":"Client attributes, use ${metaKeyName} to substitute variables from metadata","shared-attributes":"Shared attributes","shared-attributes-hint":"Shared attributes, use ${metaKeyName} to substitute variables from metadata","server-attributes":"Server attributes","server-attributes-hint":"Server attributes, use ${metaKeyName} to substitute variables from metadata","notify-device":"Notify Device","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","latest-timeseries":"Latest timeseries","latest-timeseries-hint":"Latest timeseries, use ${metaKeyName} to substitute variables from metadata","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-hint":"Relation type pattern, use ${metaKeyName} to substitute variables from metadata","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use metadata period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds metadata pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","period-in-seconds-pattern-hint":"Period in seconds pattern, use ${metaKeyName} to substitute variables from metadata","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","from-template-hint":"From address template, use ${metaKeyName} to substitute variables from metadata","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":"Comma separated address list, use ${metaKeyName} to substitute variables from metadata","cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","subject-template-hint":"Mail subject template, use ${metaKeyName} to substitute variables from metadata","body-template":"Body Template","body-template-required":"Body Template is required","body-template-hint":"Mail body template, use ${metaKeyName} to substitute variables from metadata","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","endpoint-url-pattern-hint":"HTTP URL address pattern, use ${metaKeyName} to substitute variables from metadata","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":"Use ${metaKeyName} in header/value fields to substitute variables from metadata",header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required","mqtt-topic-pattern-hint":"MQTT topic pattern, use ${metaKeyName} to substitute variables from metadata",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","topic-arn-pattern-hint":"Topic ARN pattern, use ${metaKeyName} to substitute variables from metadata","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","queue-url-pattern-hint":"Queue URL pattern, use ${metaKeyName} to substitute variables from metadata","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":"Use ${metaKeyName} in name/value fields to substitute variables from metadata","connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file *","private-key":"Client private key file *",cert:"Client certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use metadata interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","start-interval-pattern-hint":"Start interval pattern, use ${metaKeyName} to substitute variables from metadata","end-interval-pattern-hint":"End interval pattern, use ${metaKeyName} to substitute variables from metadata","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":"Comma separated Phone Numbers, use ${metaKeyName} to substitute variables from metadata","sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","sms-message-template-hint":"SMS message template, use ${metaKeyName} to substitute variables from metadata","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-zip":"Zip","entity-details-address":"Address","entity-details-address2":"Address2","entity-details-additional_info":"Additional Info","entity-details-phone":"Phone","entity-details-email":"Email","add-to-metadata":"Add selected details to message metadata","add-to-metadata-hint":"If selected, adds the selected details keys to the message metadata instead of message data.","entity-details-list-empty":"No entity details selected.","no-entity-details-matching":"No entity details matching were found.","custom-table-name":"Custom table name","custom-table-name-required":"Table Name is required","custom-table-hint":"You should enter the table name without prefix 'cs_tb_'.","message-field":"Message field","message-field-required":"Message field is required.","table-col":"Table column","table-col-required":"Table column is required.","latitude-key-name":"Latitude key name","longitude-key-name":"Longitude key name","latitude-key-name-required":"Latitude key name is required.","longitude-key-name-required":"Longitude key name is required.","fetch-perimeter-info-from-message-metadata":"Fetch perimeter information from message metadata","perimeter-circle":"Circle","perimeter-polygon":"Polygon","perimeter-type":"Perimeter type","circle-center-latitude":"Center latitude","circle-center-latitude-required":"Center latitude is required.","circle-center-longitude":"Center longitude","circle-center-longitude-required":"Center longitude is required.","range-unit-meter":"Meter","range-unit-kilometer":"Kilometer","range-unit-foot":"Foot","range-unit-mile":"Mile","range-unit-nautical-mile":"Nautical mile","range-units":"Range units",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].","min-inside-duration":"Minimal inside duration","min-inside-duration-value-required":"Minimal inside duration is required","min-inside-duration-time-unit":"Minimal inside duration time unit","min-outside-duration":"Minimal outside duration","min-outside-duration-value-required":"Minimal outside duration is required","min-outside-duration-time-unit":"Minimal outside duration time unit","tell-failure-if-absent":"Tell Failure","tell-failure-if-absent-hint":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"get-latest-value-with-ts":"Fetch Latest telemetry with Timestamp","get-latest-value-with-ts-hint":'If selected, latest telemetry values will be added to the outbound message metadata with timestamp, e.g: "temp": "{\\"ts\\":1574329385897,\\"value\\":42}"',"use-redis-queue":"Use redis queue for message persistence","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required.","output-value-key":"Output value key","output-value-key-required":"Output value key is required.",round:"Decimals","round-range":"Decimals should be in a range from 0 to 15.","use-cache":"Use cache for latest value","tell-failure-if-input-value-key-is-absent":"Tell Failure if input value key is absent","tell-failure-if-delta-is-negative":"Tell Failure if delta is negative","add-period-between-msgs":"Add period between messages","period-value-key":"Period value key","period-key-required":"Period value key is required."},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"}}},!0)}(e)}return e.ctorParameters=function(){return[{type:n.TranslateService}]},e=b([t.NgModule({declarations:[F],imports:[r.CommonModule,a.SharedModule],exports:[xe,Ae,Ge,ze,F]}),h("design:paramtypes",[n.TranslateService])],e)}();e.RuleNodeCoreConfigModule=$e,e.ɵa=F,e.ɵb=xe,e.ɵba=he,e.ɵbb=Ce,e.ɵbc=ve,e.ɵbd=Fe,e.ɵbe=se,e.ɵbf=ne,e.ɵbg=ae,e.ɵbh=oe,e.ɵbi=ie,e.ɵbj=le,e.ɵbk=Ae,e.ɵbl=Te,e.ɵbm=qe,e.ɵbn=Se,e.ɵbo=Ie,e.ɵbp=ke,e.ɵbq=Ne,e.ɵbr=Ve,e.ɵbs=Ee,e.ɵbt=Ge,e.ɵbu=Le,e.ɵbv=Me,e.ɵbw=Pe,e.ɵbx=we,e.ɵby=Re,e.ɵbz=De,e.ɵc=x,e.ɵca=Oe,e.ɵcb=Ke,e.ɵcc=Be,e.ɵcd=ze,e.ɵce=Ue,e.ɵcf=je,e.ɵcg=He,e.ɵd=T,e.ɵe=q,e.ɵf=S,e.ɵg=I,e.ɵh=k,e.ɵi=N,e.ɵj=V,e.ɵk=E,e.ɵl=A,e.ɵm=L,e.ɵn=X,e.ɵo=ee,e.ɵp=te,e.ɵq=re,e.ɵr=me,e.ɵs=ue,e.ɵt=de,e.ɵu=pe,e.ɵv=ce,e.ɵw=fe,e.ɵx=ge,e.ɵy=ye,e.ɵz=be,Object.defineProperty(e,"__esModule",{value:!0})})); //# sourceMappingURL=rulenode-core-config.umd.min.js.map \ No newline at end of file From 99ca70f3756cc0c638bd623393a2480bdf1aae85 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 3 Feb 2021 16:58:21 +0200 Subject: [PATCH 112/249] ui refactoring --- .../resources/public/static/rulenode/rulenode-core-config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js index b747cd797d..ee8b765456 100644 --- a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js +++ b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js @@ -12,5 +12,5 @@ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - ***************************************************************************** */var g=function(e,t){return(g=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])})(e,t)};function y(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}g(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}function b(e,t,r,n){var a,o=arguments.length,i=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,r,n);else for(var l=e.length-1;l>=0;l--)(a=e[l])&&(i=(o<3?a(i):o>3?a(t,r,i):a(t,r))||i);return o>3&&i&&Object.defineProperty(t,r,i),i}function h(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}Object.create;function C(e){var t="function"==typeof Symbol&&Symbol.iterator,r=t&&e[t],n=0;if(r)return r.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}Object.create;var v,F=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.emptyConfigForm},r.prototype.onConfigurationSet=function(e){this.emptyConfigForm=this.fb.group({})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-node-empty-config",template:"
"}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),x=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return y(r,e),r.prototype.configForm=function(){return this.attributesConfigForm},r.prototype.onConfigurationSet=function(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]],notifyDevice:[!e||e.scope,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-attributes-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),T=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.timeseriesConfigForm},r.prototype.onConfigurationSet=function(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-timeseries-config",template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),q=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.rpcRequestConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rpc-request-config",template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),S=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.logConfigForm},r.prototype.onConfigurationSet=function(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.logConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-log-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),I=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.assignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),k=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.clearAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],alarmType:[e?e.alarmType:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-clear-alarm-config",template:'
\n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),N=function(e){function r(t,r,n,o){var i=e.call(this,t)||this;return i.store=t,i.fb=r,i.nodeScriptTestService=n,i.translate=o,i.alarmSeverities=Object.keys(a.AlarmSeverity),i.alarmSeverityTranslationMap=a.alarmSeverityTranslations,i.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],i}return y(r,e),r.prototype.configForm=function(){return this.createAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]]})},r.prototype.validatorTriggers=function(){return["useMessageAlarmData"]},r.prototype.updateValidators=function(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([i.Validators.required]),this.createAlarmConfigForm.get("severity").setValidators([i.Validators.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})},r.prototype.testScript=function(){var e=this,t=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.removeKey=function(e,t){var r=this.createAlarmConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.createAlarmConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.createAlarmConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.createAlarmConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-create-alarm-config",template:'
\n \n \n \n
\n \n
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n \n \n
\n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),V=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return y(r,e),r.prototype.configForm=function(){return this.createRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[i.Validators.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["entityType"]},r.prototype.updateValidators=function(e){var t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==a.EntityType.DEVICE&&t!==a.EntityType.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([i.Validators.required]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-create-relation-config",template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),E=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.msgDelayConfigForm},r.prototype.onConfigurationSet=function(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(1e5)]]})},r.prototype.validatorTriggers=function(){return["useMetadataPeriodInSecondsPatterns"]},r.prototype.updateValidators=function(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([i.Validators.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([i.Validators.required,i.Validators.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-msg-delay-config",template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),A=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return y(r,e),r.prototype.configForm=function(){return this.deleteRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["deleteForSingleEntity","entityType"]},r.prototype.updateValidators=function(e){var t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,r=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&r?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-delete-relation-config",template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),L=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.generatorConfigForm},r.prototype.onConfigurationSet=function(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[i.Validators.required,i.Validators.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[i.Validators.required,i.Validators.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.prepareInputConfig=function(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e},r.prototype.prepareOutputConfig=function(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e},r.prototype.testScript=function(){var e=this,t=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId).subscribe((function(t){t&&e.generatorConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-generator-config",template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent);!function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(v||(v={}));var M,P=new Map([[v.CUSTOMER,"tb.rulenode.originator-customer"],[v.TENANT,"tb.rulenode.originator-tenant"],[v.RELATED,"tb.rulenode.originator-related"],[v.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(M||(M={}));var w,R=new Map([[M.CIRCLE,"tb.rulenode.perimeter-circle"],[M.POLYGON,"tb.rulenode.perimeter-polygon"]]);!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(w||(w={}));var D,O=new Map([[w.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[w.SECONDS,"tb.rulenode.time-unit-seconds"],[w.MINUTES,"tb.rulenode.time-unit-minutes"],[w.HOURS,"tb.rulenode.time-unit-hours"],[w.DAYS,"tb.rulenode.time-unit-days"]]);!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(D||(D={}));var K,B=new Map([[D.METER,"tb.rulenode.range-unit-meter"],[D.KILOMETER,"tb.rulenode.range-unit-kilometer"],[D.FOOT,"tb.rulenode.range-unit-foot"],[D.MILE,"tb.rulenode.range-unit-mile"],[D.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(K||(K={}));var G,U,j,H=new Map([[K.TITLE,"tb.rulenode.entity-details-title"],[K.COUNTRY,"tb.rulenode.entity-details-country"],[K.STATE,"tb.rulenode.entity-details-state"],[K.ZIP,"tb.rulenode.entity-details-zip"],[K.ADDRESS,"tb.rulenode.entity-details-address"],[K.ADDRESS2,"tb.rulenode.entity-details-address2"],[K.PHONE,"tb.rulenode.entity-details-phone"],[K.EMAIL,"tb.rulenode.entity-details-email"],[K.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(G||(G={})),function(e){e.ASC="ASC",e.DESC="DESC"}(U||(U={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(j||(j={}));var z,$=new Map([[j.STANDARD,"tb.rulenode.sqs-queue-standard"],[j.FIFO,"tb.rulenode.sqs-queue-fifo"]]),Q=["anonymous","basic","cert.PEM"],_=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),W=["sas","cert.PEM"],J=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(z||(z={}));var Y=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],Z=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]),X=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=R,n.rangeUnits=Object.keys(D),n.rangeUnitTranslationMap=B,n.timeUnits=Object.keys(w),n.timeUnitsTranslationMap=O,n}return y(r,e),r.prototype.configForm=function(){return this.geoActionConfigForm},r.prototype.onConfigurationSet=function(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[i.Validators.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterType").setValidators([]):this.geoActionConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoActionConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoActionConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.msgCountConfigForm},r.prototype.onConfigurationSet=function(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[i.Validators.required,i.Validators.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-msg-count-config",template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.rpcReplyConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rpc-reply-config",template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.saveToCustomTableConfigForm},r.prototype.onConfigurationSet=function(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[i.Validators.required]],fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-custom-table-config",template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n \n \n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ne=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.translate=r,o.injector=n,o.fb=a,o.propagateChange=null,o.valueChangeSubscription=null,o}var a;return y(r,e),a=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){this.ngControl=this.injector.get(i.NgControl),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))},r.prototype.keyValsFormArray=function(){return this.kvListFormGroup.get("keyVals")},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t,r,n=this;this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();var a=[];if(e)try{for(var o=C(Object.keys(e)),l=o.next();!l.done;l=o.next()){var s=l.value;Object.prototype.hasOwnProperty.call(e,s)&&a.push(this.fb.group({key:[s,[i.Validators.required]],value:[e[s],[i.Validators.required]]}))}}catch(e){t={error:e}}finally{try{l&&!l.done&&(r=o.return)&&r.call(o)}finally{if(t)throw t.error}}this.kvListFormGroup.setControl("keyVals",this.fb.array(a)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((function(){n.updateModel()}))},r.prototype.removeKeyVal=function(e){this.kvListFormGroup.get("keyVals").removeAt(e)},r.prototype.addKeyVal=function(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[i.Validators.required]],value:["",[i.Validators.required]]}))},r.prototype.validate=function(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}},r.prototype.updateModel=function(){var e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{var t={};e.forEach((function(e){t[e.key]=e.value})),this.propagateChange(t)}},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:t.Injector},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",String)],r.prototype,"requiredText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"keyText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"keyRequiredText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"valText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"valRequiredText",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=a=b([t.Component({selector:"tb-kv-map-config",template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n \n
\n \n
\n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return a})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return a})),multi:!0}],styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:rgba(0,0,0,.54);font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}"]}),h("design:paramtypes",[o.Store,n.TranslateService,t.Injector,i.FormBuilder])],r)}(a.PageComponent),ae=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n.propagateChange=null,n}var n;return y(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[i.Validators.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((function(t){e.deviceRelationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=b([t.Component({selector:"tb-device-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-type
\n \n \n
device.device-types
\n \n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.propagateChange=null,n}var n;return y(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((function(t){e.relationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=b([t.Component({selector:"tb-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),ie=function(e){function r(t,r,n,o){var i,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.truncate=n,s.fb=o,s.placeholder="tb.rulenode.message-type",s.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],s.messageTypes=[],s.messageTypesList=[],s.searchText="",s.propagateChange=function(e){},s.messageTypeConfigForm=s.fb.group({messageType:[null]});try{for(var u=C(Object.keys(a.MessageType)),d=u.next();!d.done;d=u.next()){var p=d.value;s.messageTypesList.push({name:a.messageTypeNames.get(a.MessageType[p]),value:p})}}catch(e){i={error:e}}finally{try{d&&!d.done&&(l=u.return)&&l.call(u)}finally{if(i)throw i.error}}return s}var l;return y(r,e),l=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.ngOnInit=function(){var e=this;this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(t){return e.fetchMessageTypes(t)})),f.share())},r.prototype.ngAfterViewInit=function(){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t=this;this.searchText="",this.messageTypes.length=0,e&&e.forEach((function(e){var r=t.messageTypesList.find((function(t){return t.value===e}));r?t.messageTypes.push({name:r.name,value:r.value}):t.messageTypes.push({name:e,value:e})}))},r.prototype.displayMessageTypeFn=function(e){return e?e.name:void 0},r.prototype.textIsNotEmpty=function(e){return!!(e&&null!=e&&e.length>0)},r.prototype.createMessageType=function(e,t){e.preventDefault(),this.transformMessageType(t)},r.prototype.add=function(e){this.transformMessageType(e.value)},r.prototype.fetchMessageTypes=function(e){if(this.searchText=e,this.searchText&&this.searchText.length){var t=this.searchText.toUpperCase();return c.of(this.messageTypesList.filter((function(e){return e.name.toUpperCase().includes(t)})))}return c.of(this.messageTypesList)},r.prototype.transformMessageType=function(e){if((e||"").trim()){var t=null,r=e.trim(),n=this.messageTypesList.find((function(e){return e.name===r}));(t=n?{name:n.name,value:n.value}:{name:r,value:r})&&this.addMessageType(t)}this.clear("")},r.prototype.remove=function(e){var t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())},r.prototype.selected=function(e){this.addMessageType(e.option.value),this.clear("")},r.prototype.addMessageType=function(e){-1===this.messageTypes.findIndex((function(t){return t.value===e.value}))&&(this.messageTypes.push(e),this.updateModel())},r.prototype.onFocus=function(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((function(){t.messageTypeInput.nativeElement.blur(),t.messageTypeInput.nativeElement.focus()}),0)},r.prototype.updateModel=function(){var e=this.messageTypes.map((function(e){return e.value}));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:a.TruncatePipe},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),b([t.Input(),h("design:type",String)],r.prototype,"label",void 0),b([t.Input(),h("design:type",Object)],r.prototype,"placeholder",void 0),b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.ViewChild("chipList",{static:!1}),h("design:type",d.MatChipList)],r.prototype,"chipList",void 0),b([t.ViewChild("messageTypeAutocomplete",{static:!1}),h("design:type",p.MatAutocomplete)],r.prototype,"matAutocomplete",void 0),b([t.ViewChild("messageTypeInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"messageTypeInput",void 0),r=l=b([t.Component({selector:"tb-message-types-config",template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return l})),multi:!0}]}),h("design:paramtypes",[o.Store,n.TranslateService,a.TruncatePipe,i.FormBuilder])],r)}(a.PageComponent),le=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.subscriptions=[],n.disableCertPemCredentials=!1,n.allCredentialsTypes=Q,n.credentialsTypeTranslationsMap=_,n.propagateChange=null,n}var n;return y(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.credentialsConfigFormGroup=this.fb.group({type:[null,[i.Validators.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(f.distinctUntilChanged()).subscribe((function(){e.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((function(){e.credentialsTypeChanged()})))},r.prototype.ngOnChanges=function(e){var t,r,n=this;try{for(var a=C(Object.keys(e)),o=a.next();!o.done;o=a.next()){var i=o.value,l=e[i];if(!l.firstChange&&l.currentValue!==l.previousValue)if(l.currentValue&&"disableCertPemCredentials"===i)"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((function(){n.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}catch(e){t={error:e}}finally{try{o&&!o.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}},r.prototype.ngOnDestroy=function(){this.subscriptions.forEach((function(e){return e.unsubscribe()}))},r.prototype.writeValue=function(e){s.isDefinedAndNotNull(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))},r.prototype.setDisabledState=function(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())},r.prototype.updateView=function(){var e=this.credentialsConfigFormGroup.value,t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.validate=function(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}},r.prototype.credentialsTypeChanged=function(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()},r.prototype.updateValidators=function(e){void 0===e&&(e=!1);var t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([i.Validators.required]),this.credentialsConfigFormGroup.get("password").setValidators([i.Validators.required]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(i.Validators.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})},r.prototype.requiredFilesSelected=function(e,t){return void 0===t&&(t=null),function(r){return t||(t=[Object.keys(r.controls)]),(null==r?void 0:r.controls)&&t.some((function(t){return t.every((function(t){return!e(r.controls[t])}))}))?null:{notAllRequiredFilesSelected:!0}}},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),b([t.Input(),h("design:type",Object)],r.prototype,"disableCertPemCredentials",void 0),r=n=b([t.Component({selector:"tb-credentials-config",template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n
\n
\n
\n
\n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),se=function(){function e(){}return e=b([t.NgModule({declarations:[ne,ae,oe,ie,le],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule],exports:[ne,ae,oe,ie,le]})],e)}(),me=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.unassignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-un-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ue=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.snsConfigForm},r.prototype.onConfigurationSet=function(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[i.Validators.required]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-sns-config",template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),de=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.sqsQueueType=j,n.sqsQueueTypes=Object.keys(j),n.sqsQueueTypeTranslationsMap=$,n}return y(r,e),r.prototype.configForm=function(){return this.sqsConfigForm},r.prototype.onConfigurationSet=function(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[i.Validators.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[i.Validators.required]],delaySeconds:[e?e.delaySeconds:null,[i.Validators.min(0),i.Validators.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-sqs-config",template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.pubSubConfigForm},r.prototype.onConfigurationSet=function(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[i.Validators.required]],topicName:[e?e.topicName:null,[i.Validators.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[i.Validators.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[i.Validators.required]],messageAttributes:[e?e.messageAttributes:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-pub-sub-config",template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.ackValues=["all","-1","0","1"],n.ToByteStandartCharsetTypesValues=Y,n.ToByteStandartCharsetTypeTranslationMap=Z,n}return y(r,e),r.prototype.configForm=function(){return this.kafkaConfigForm},r.prototype.onConfigurationSet=function(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],bootstrapServers:[e?e.bootstrapServers:null,[i.Validators.required]],retries:[e?e.retries:null,[i.Validators.min(0)]],batchSize:[e?e.batchSize:null,[i.Validators.min(0)]],linger:[e?e.linger:null,[i.Validators.min(0)]],bufferMemory:[e?e.bufferMemory:null,[i.Validators.min(0)]],acks:[e?e.acks:null,[i.Validators.required]],keySerializer:[e?e.keySerializer:null,[i.Validators.required]],valueSerializer:[e?e.valueSerializer:null,[i.Validators.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})},r.prototype.validatorTriggers=function(){return["addMetadataKeyValuesAsKafkaHeaders"]},r.prototype.updateValidators=function(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([i.Validators.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-kafka-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.mqttConfigForm},r.prototype.onConfigurationSet=function(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-mqtt-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n \n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],n}return y(r,e),r.prototype.configForm=function(){return this.rabbitMqConfigForm},r.prototype.onConfigurationSet=function(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[i.Validators.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[i.Validators.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rabbit-mq-config",template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ye=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.proxySchemes=["http","https"],n.httpRequestTypes=Object.keys(z),n}return y(r,e),r.prototype.configForm=function(){return this.restApiCallConfigForm},r.prototype.onConfigurationSet=function(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[i.Validators.required]],requestMethod:[e?e.requestMethod:null,[i.Validators.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[i.Validators.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})},r.prototype.validatorTriggers=function(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]},r.prototype.updateValidators=function(e){var t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,r=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,n=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;n&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(n?[i.Validators.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(n?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([i.Validators.min(0)])),r?this.restApiCallConfigForm.get("maxQueueSize").setValidators([i.Validators.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rest-api-call-config",template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n \n \n \n tb.rulenode.max-parallel-requests-count\n \n \n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.smtpProtocols=["smtp","smtps"],n.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"],n}return y(r,e),r.prototype.configForm=function(){return this.sendEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmtpSettings","enableProxy"]},r.prototype.updateValidators=function(e){var t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,r=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([i.Validators.required,i.Validators.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(r?[i.Validators.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(r?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-send-email-config",template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),he=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.serviceType=a.ServiceType.TB_RULE_ENGINE,n}return y(r,e),r.prototype.configForm=function(){return this.checkPointConfigForm},r.prototype.onConfigurationSet=function(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-check-point-config",template:'
\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allAzureIotHubCredentialsTypes=W,n.azureIotHubCredentialsTypeTranslationsMap=J,n}return y(r,e),r.prototype.configForm=function(){return this.azureIotHubConfigForm},r.prototype.onConfigurationSet=function(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[i.Validators.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[i.Validators.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})},r.prototype.prepareOutputConfig=function(e){var t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e},r.prototype.validatorTriggers=function(){return["credentials.type"]},r.prototype.updateValidators=function(e){var t=this.azureIotHubConfigForm.get("credentials"),r=t.get("type").value;switch(e&&t.reset({type:r},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),r){case"sas":t.get("sasKey").setValidators([i.Validators.required]);break;case"cert.PEM":t.get("privateKey").setValidators([i.Validators.required]),t.get("privateKeyFileName").setValidators([i.Validators.required]),t.get("cert").setValidators([i.Validators.required]),t.get("certFileName").setValidators([i.Validators.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-azure-iot-hub-config",template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.deviceProfile},r.prototype.onConfigurationSet=function(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,i.Validators.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,i.Validators.required]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-device-profile-config",template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.sendSmsConfigForm},r.prototype.onConfigurationSet=function(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[i.Validators.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[i.Validators.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmsSettings"]},r.prototype.updateValidators=function(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([i.Validators.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-send-sms-config",template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),xe=function(){function e(){}return e=b([t.NgModule({declarations:[x,T,q,S,I,k,N,V,E,A,L,X,ee,te,re,me,ue,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule,se],exports:[x,T,q,S,I,k,N,V,E,A,L,X,ee,te,re,me,ue,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe]})],e)}(),Te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.checkMessageConfigForm},r.prototype.onConfigurationSet=function(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})},r.prototype.validateConfig=function(){var e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0},r.prototype.removeMessageName=function(e){var t=this.checkMessageConfigForm.get("messageNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))},r.prototype.removeMetadataName=function(e){var t=this.checkMessageConfigForm.get("metadataNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))},r.prototype.addMessageName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("messageNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("messageNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.prototype.addMetadataName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("metadataNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("metadataNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-check-message-config",template:'
\n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),qe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.entitySearchDirection=Object.keys(a.EntitySearchDirection),n.entitySearchDirectionTranslationsMap=a.entitySearchDirectionTranslations,n}return y(r,e),r.prototype.configForm=function(){return this.checkRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],relationType:[e?e.relationType:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["checkForSingleEntity"]},r.prototype.updateValidators=function(e){var t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-check-relation-config",template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=R,n.rangeUnits=Object.keys(D),n.rangeUnitTranslationMap=B,n}return y(r,e),r.prototype.configForm=function(){return this.geoFilterConfigForm},r.prototype.onConfigurationSet=function(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterType").setValidators([]):this.geoFilterConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoFilterConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoFilterConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ie=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.messageTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-message-type-config",template:'
\n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allowedEntityTypes=[a.EntityType.DEVICE,a.EntityType.ASSET,a.EntityType.ENTITY_VIEW,a.EntityType.TENANT,a.EntityType.CUSTOMER,a.EntityType.USER,a.EntityType.DASHBOARD,a.EntityType.RULE_CHAIN,a.EntityType.RULE_NODE],n}return y(r,e),r.prototype.configForm=function(){return this.originatorTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-originator-type-config",template:'
\n \n \n \n
\n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ne=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-filter-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Ve=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.switchConfigForm},r.prototype.onConfigurationSet=function(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.switchConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-filter-node-switch-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Ee=function(e){function r(t,r,n){var o,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.fb=n,s.alarmStatusTranslationsMap=a.alarmStatusTranslations,s.alarmStatusList=[],s.searchText="",s.displayStatusFn=s.displayStatus.bind(s);try{for(var m=C(Object.keys(a.AlarmStatus)),u=m.next();!u.done;u=m.next()){var d=u.value;s.alarmStatusList.push(a.AlarmStatus[d])}}catch(e){o={error:e}}finally{try{u&&!u.done&&(l=m.return)&&l.call(m)}finally{if(o)throw o.error}}return s.statusFormControl=new i.FormControl(""),s.filteredAlarmStatus=s.statusFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return s.fetchAlarmStatus(e)})),f.share()),s}return y(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.alarmStatusConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[i.Validators.required]]})},r.prototype.displayStatus=function(e){return e?this.translate.instant(a.alarmStatusTranslations.get(e)):void 0},r.prototype.fetchAlarmStatus=function(e){var t=this,r=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){var n=this.searchText.toUpperCase();return c.of(r.filter((function(e){return t.translate.instant(a.alarmStatusTranslations.get(a.AlarmStatus[e])).toUpperCase().includes(n)})))}return c.of(r)},r.prototype.alarmStatusSelected=function(e){this.addAlarmStatus(e.option.value),this.clear("")},r.prototype.removeAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}},r.prototype.addAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))},r.prototype.getAlarmStatusList=function(){var e=this;return this.alarmStatusList.filter((function(t){return-1===e.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(t)}))},r.prototype.onAlarmStatusInputFocus=function(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.alarmStatusInput.nativeElement.blur(),t.alarmStatusInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},b([t.ViewChild("alarmStatusInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"alarmStatusInput",void 0),r=b([t.Component({selector:"tb-filter-node-check-alarm-status-config",template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n'}),h("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ae=function(){function e(){}return e=b([t.NgModule({declarations:[Te,qe,Se,Ie,ke,Ne,Ve,Ee],imports:[r.CommonModule,a.SharedModule,se],exports:[Te,qe,Se,Ie,ke,Ne,Ve,Ee]})],e)}(),Le=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.customerAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-customer-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Me=function(e){function r(t,r,n){var a,o,l=e.call(this,t)||this;l.store=t,l.translate=r,l.fb=n,l.entityDetailsTranslationsMap=H,l.entityDetailsList=[],l.searchText="",l.displayDetailsFn=l.displayDetails.bind(l);try{for(var s=C(Object.keys(K)),m=s.next();!m.done;m=s.next()){var u=m.value;l.entityDetailsList.push(K[u])}}catch(e){a={error:e}}finally{try{m&&!m.done&&(o=s.return)&&o.call(s)}finally{if(a)throw a.error}}return l.detailsFormControl=new i.FormControl(""),l.filteredEntityDetails=l.detailsFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return l.fetchEntityDetails(e)})),f.share()),l}return y(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.entityDetailsConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[i.Validators.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})},r.prototype.displayDetails=function(e){return e?this.translate.instant(H.get(e)):void 0},r.prototype.fetchEntityDetails=function(e){var t=this;if(this.searchText=e,this.searchText&&this.searchText.length){var r=this.searchText.toUpperCase();return c.of(this.entityDetailsList.filter((function(e){return t.translate.instant(H.get(K[e])).toUpperCase().includes(r)})))}return c.of(this.entityDetailsList)},r.prototype.detailsFieldSelected=function(e){this.addDetailsField(e.option.value),this.clear("")},r.prototype.removeDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}},r.prototype.addDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))},r.prototype.onEntityDetailsInputFocus=function(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.detailsInput.nativeElement.blur(),t.detailsInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},b([t.ViewChild("detailsInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"detailsInput",void 0),r=b([t.Component({selector:"tb-enrichment-node-entity-details-config",template:'
\n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-entity-details-matching\n
\n
\n
\n
\n
\n \n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
tb.rulenode.add-to-metadata-hint
\n
\n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}"]}),h("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.deviceAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[i.Validators.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.deviceAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.deviceAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.deviceAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.deviceAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-device-attributes-config",template:'
\n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),we=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.originatorAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.originatorAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.originatorAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.originatorAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.originatorAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-originator-attributes-config",template:'
\n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.originatorFieldsConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-originator-fields-config",template:'
\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),De=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n.fetchMode=G,n.fetchModes=Object.keys(G),n.samplingOrders=Object.keys(U),n.timeUnits=Object.keys(w),n.timeUnitsTranslationMap=O,n}return y(r,e),r.prototype.configForm=function(){return this.getTelemetryFromDatabaseConfigForm},r.prototype.onConfigurationSet=function(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],fetchMode:[e?e.fetchMode:null,[i.Validators.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchMode","useMetadataIntervalPatterns"]},r.prototype.updateValidators=function(e){var t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,r=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===G.ALL?(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([i.Validators.required,i.Validators.min(2),i.Validators.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),r?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([i.Validators.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})},r.prototype.removeKey=function(e,t){var r=this.getTelemetryFromDatabaseConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.getTelemetryFromDatabaseConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-get-telemetry-from-database",template:'
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
\n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
\n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-interval-patterns-hint
\n
\n
\n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.relatedAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[i.Validators.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-related-attributes-config",template:'
\n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.tenantAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-tenant-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.calculateDeltaConfigForm},r.prototype.onConfigurationSet=function(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e?e.inputValueKey:null,[i.Validators.required]],outputValueKey:[e?e.outputValueKey:null,[i.Validators.required]],useCache:[e?e.useCache:null,[]],addPeriodBetweenMsgs:[!!e&&e.addPeriodBetweenMsgs,[]],periodValueKey:[e?e.periodValueKey:null,[]],round:[e?e.round:null,[i.Validators.min(0),i.Validators.max(15)]],tellFailureIfInputValueKeyIsAbsent:[e?e.tellFailureIfInputValueKeyIsAbsent:null,[]],tellFailureIfDeltaIsNegative:[e?e.tellFailureIfDeltaIsNegative:null,[]]})},r.prototype.updateValidators=function(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([i.Validators.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("inputValueKey").updateValueAndValidity({emitEvent:e}),this.calculateDeltaConfigForm.get("outputValueKey").updateValueAndValidity({emitEvent:e}),this.calculateDeltaConfigForm.get("round").updateValueAndValidity({emitEvent:e}),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})},r.prototype.validatorTriggers=function(){return["addPeriodBetweenMsgs"]},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-calculate-delta-config",template:'
\n
\n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-input-value-key-is-absent\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ge=function(){function e(){}return e=b([t.NgModule({declarations:[Le,Me,Pe,we,Re,De,Oe,Ke,Be],imports:[r.CommonModule,a.SharedModule,se],exports:[Le,Me,Pe,we,Re,De,Oe,Ke,Be]})],e)}(),Ue=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.originatorSource=v,n.originatorSources=Object.keys(v),n.originatorSourceTranslationMap=P,n}return y(r,e),r.prototype.configForm=function(){return this.changeOriginatorConfigForm},r.prototype.onConfigurationSet=function(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[i.Validators.required]],relationsQuery:[e?e.relationsQuery:null,[]]})},r.prototype.validatorTriggers=function(){return["originatorSource"]},r.prototype.updateValidators=function(e){var t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===v.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([i.Validators.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-transformation-node-change-originator-config",template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),je=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-transformation-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),He=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.toEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[i.Validators.required]],toTemplate:[e?e.toTemplate:null,[i.Validators.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[i.Validators.required]],bodyTemplate:[e?e.bodyTemplate:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-transformation-node-to-email-config",template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ze=function(){function e(){}return e=b([t.NgModule({declarations:[Ue,je,He],imports:[r.CommonModule,a.SharedModule,se],exports:[Ue,je,He]})],e)}(),$e=function(){function e(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-name-pattern-hint":"Name pattern, use ${metaKeyName} to substitute variables from metadata","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-type-pattern-hint":"Type pattern, use ${metaKeyName} to substitute variables from metadata","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-name-pattern-hint":"Customer name pattern, use ${metaKeyName} to substitute variables from metadata","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","client-attributes-hint":"Client attributes, use ${metaKeyName} to substitute variables from metadata","shared-attributes":"Shared attributes","shared-attributes-hint":"Shared attributes, use ${metaKeyName} to substitute variables from metadata","server-attributes":"Server attributes","server-attributes-hint":"Server attributes, use ${metaKeyName} to substitute variables from metadata","notify-device":"Notify Device","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","latest-timeseries":"Latest timeseries","latest-timeseries-hint":"Latest timeseries, use ${metaKeyName} to substitute variables from metadata","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-hint":"Relation type pattern, use ${metaKeyName} to substitute variables from metadata","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use metadata period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds metadata pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","period-in-seconds-pattern-hint":"Period in seconds pattern, use ${metaKeyName} to substitute variables from metadata","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","from-template-hint":"From address template, use ${metaKeyName} to substitute variables from metadata","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":"Comma separated address list, use ${metaKeyName} to substitute variables from metadata","cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","subject-template-hint":"Mail subject template, use ${metaKeyName} to substitute variables from metadata","body-template":"Body Template","body-template-required":"Body Template is required","body-template-hint":"Mail body template, use ${metaKeyName} to substitute variables from metadata","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","endpoint-url-pattern-hint":"HTTP URL address pattern, use ${metaKeyName} to substitute variables from metadata","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":"Use ${metaKeyName} in header/value fields to substitute variables from metadata",header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required","mqtt-topic-pattern-hint":"MQTT topic pattern, use ${metaKeyName} to substitute variables from metadata",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","topic-arn-pattern-hint":"Topic ARN pattern, use ${metaKeyName} to substitute variables from metadata","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","queue-url-pattern-hint":"Queue URL pattern, use ${metaKeyName} to substitute variables from metadata","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":"Use ${metaKeyName} in name/value fields to substitute variables from metadata","connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file *","private-key":"Client private key file *",cert:"Client certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use metadata interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","start-interval-pattern-hint":"Start interval pattern, use ${metaKeyName} to substitute variables from metadata","end-interval-pattern-hint":"End interval pattern, use ${metaKeyName} to substitute variables from metadata","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":"Comma separated Phone Numbers, use ${metaKeyName} to substitute variables from metadata","sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","sms-message-template-hint":"SMS message template, use ${metaKeyName} to substitute variables from metadata","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-zip":"Zip","entity-details-address":"Address","entity-details-address2":"Address2","entity-details-additional_info":"Additional Info","entity-details-phone":"Phone","entity-details-email":"Email","add-to-metadata":"Add selected details to message metadata","add-to-metadata-hint":"If selected, adds the selected details keys to the message metadata instead of message data.","entity-details-list-empty":"No entity details selected.","no-entity-details-matching":"No entity details matching were found.","custom-table-name":"Custom table name","custom-table-name-required":"Table Name is required","custom-table-hint":"You should enter the table name without prefix 'cs_tb_'.","message-field":"Message field","message-field-required":"Message field is required.","table-col":"Table column","table-col-required":"Table column is required.","latitude-key-name":"Latitude key name","longitude-key-name":"Longitude key name","latitude-key-name-required":"Latitude key name is required.","longitude-key-name-required":"Longitude key name is required.","fetch-perimeter-info-from-message-metadata":"Fetch perimeter information from message metadata","perimeter-circle":"Circle","perimeter-polygon":"Polygon","perimeter-type":"Perimeter type","circle-center-latitude":"Center latitude","circle-center-latitude-required":"Center latitude is required.","circle-center-longitude":"Center longitude","circle-center-longitude-required":"Center longitude is required.","range-unit-meter":"Meter","range-unit-kilometer":"Kilometer","range-unit-foot":"Foot","range-unit-mile":"Mile","range-unit-nautical-mile":"Nautical mile","range-units":"Range units",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].","min-inside-duration":"Minimal inside duration","min-inside-duration-value-required":"Minimal inside duration is required","min-inside-duration-time-unit":"Minimal inside duration time unit","min-outside-duration":"Minimal outside duration","min-outside-duration-value-required":"Minimal outside duration is required","min-outside-duration-time-unit":"Minimal outside duration time unit","tell-failure-if-absent":"Tell Failure","tell-failure-if-absent-hint":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"get-latest-value-with-ts":"Fetch Latest telemetry with Timestamp","get-latest-value-with-ts-hint":'If selected, latest telemetry values will be added to the outbound message metadata with timestamp, e.g: "temp": "{\\"ts\\":1574329385897,\\"value\\":42}"',"use-redis-queue":"Use redis queue for message persistence","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required.","output-value-key":"Output value key","output-value-key-required":"Output value key is required.",round:"Decimals","round-range":"Decimals should be in a range from 0 to 15.","use-cache":"Use cache for latest value","tell-failure-if-input-value-key-is-absent":"Tell Failure if input value key is absent","tell-failure-if-delta-is-negative":"Tell Failure if delta is negative","add-period-between-msgs":"Add period between messages","period-value-key":"Period value key","period-key-required":"Period value key is required."},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"}}},!0)}(e)}return e.ctorParameters=function(){return[{type:n.TranslateService}]},e=b([t.NgModule({declarations:[F],imports:[r.CommonModule,a.SharedModule],exports:[xe,Ae,Ge,ze,F]}),h("design:paramtypes",[n.TranslateService])],e)}();e.RuleNodeCoreConfigModule=$e,e.ɵa=F,e.ɵb=xe,e.ɵba=he,e.ɵbb=Ce,e.ɵbc=ve,e.ɵbd=Fe,e.ɵbe=se,e.ɵbf=ne,e.ɵbg=ae,e.ɵbh=oe,e.ɵbi=ie,e.ɵbj=le,e.ɵbk=Ae,e.ɵbl=Te,e.ɵbm=qe,e.ɵbn=Se,e.ɵbo=Ie,e.ɵbp=ke,e.ɵbq=Ne,e.ɵbr=Ve,e.ɵbs=Ee,e.ɵbt=Ge,e.ɵbu=Le,e.ɵbv=Me,e.ɵbw=Pe,e.ɵbx=we,e.ɵby=Re,e.ɵbz=De,e.ɵc=x,e.ɵca=Oe,e.ɵcb=Ke,e.ɵcc=Be,e.ɵcd=ze,e.ɵce=Ue,e.ɵcf=je,e.ɵcg=He,e.ɵd=T,e.ɵe=q,e.ɵf=S,e.ɵg=I,e.ɵh=k,e.ɵi=N,e.ɵj=V,e.ɵk=E,e.ɵl=A,e.ɵm=L,e.ɵn=X,e.ɵo=ee,e.ɵp=te,e.ɵq=re,e.ɵr=me,e.ɵs=ue,e.ɵt=de,e.ɵu=pe,e.ɵv=ce,e.ɵw=fe,e.ɵx=ge,e.ɵy=ye,e.ɵz=be,Object.defineProperty(e,"__esModule",{value:!0})})); + ***************************************************************************** */var g=function(e,t){return(g=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])})(e,t)};function y(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}g(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}function b(e,t,r,n){var a,o=arguments.length,i=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,r,n);else for(var l=e.length-1;l>=0;l--)(a=e[l])&&(i=(o<3?a(i):o>3?a(t,r,i):a(t,r))||i);return o>3&&i&&Object.defineProperty(t,r,i),i}function h(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}Object.create;function C(e){var t="function"==typeof Symbol&&Symbol.iterator,r=t&&e[t],n=0;if(r)return r.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}Object.create;var v,F=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.emptyConfigForm},r.prototype.onConfigurationSet=function(e){this.emptyConfigForm=this.fb.group({})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-node-empty-config",template:"
"}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),x=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return y(r,e),r.prototype.configForm=function(){return this.attributesConfigForm},r.prototype.onConfigurationSet=function(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]],notifyDevice:[!e||e.scope,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-attributes-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),T=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.timeseriesConfigForm},r.prototype.onConfigurationSet=function(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-timeseries-config",template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),q=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.rpcRequestConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rpc-request-config",template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),S=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.logConfigForm},r.prototype.onConfigurationSet=function(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.logConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-log-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),I=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.assignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),k=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.clearAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],alarmType:[e?e.alarmType:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-clear-alarm-config",template:'
\n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),N=function(e){function r(t,r,n,o){var i=e.call(this,t)||this;return i.store=t,i.fb=r,i.nodeScriptTestService=n,i.translate=o,i.alarmSeverities=Object.keys(a.AlarmSeverity),i.alarmSeverityTranslationMap=a.alarmSeverityTranslations,i.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],i}return y(r,e),r.prototype.configForm=function(){return this.createAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]]})},r.prototype.validatorTriggers=function(){return["useMessageAlarmData"]},r.prototype.updateValidators=function(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([i.Validators.required]),this.createAlarmConfigForm.get("severity").setValidators([i.Validators.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})},r.prototype.testScript=function(){var e=this,t=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.removeKey=function(e,t){var r=this.createAlarmConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.createAlarmConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.createAlarmConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.createAlarmConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-create-alarm-config",template:'
\n \n \n \n
\n \n
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n \n \n
\n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),V=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return y(r,e),r.prototype.configForm=function(){return this.createRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[i.Validators.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["entityType"]},r.prototype.updateValidators=function(e){var t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==a.EntityType.DEVICE&&t!==a.EntityType.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([i.Validators.required]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-create-relation-config",template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),E=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.msgDelayConfigForm},r.prototype.onConfigurationSet=function(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(1e5)]]})},r.prototype.validatorTriggers=function(){return["useMetadataPeriodInSecondsPatterns"]},r.prototype.updateValidators=function(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([i.Validators.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([i.Validators.required,i.Validators.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-msg-delay-config",template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),A=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return y(r,e),r.prototype.configForm=function(){return this.deleteRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["deleteForSingleEntity","entityType"]},r.prototype.updateValidators=function(e){var t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,r=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&r?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-delete-relation-config",template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),L=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.generatorConfigForm},r.prototype.onConfigurationSet=function(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[i.Validators.required,i.Validators.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[i.Validators.required,i.Validators.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.prepareInputConfig=function(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e},r.prototype.prepareOutputConfig=function(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e},r.prototype.testScript=function(){var e=this,t=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId).subscribe((function(t){t&&e.generatorConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-generator-config",template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent);!function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(v||(v={}));var M,P=new Map([[v.CUSTOMER,"tb.rulenode.originator-customer"],[v.TENANT,"tb.rulenode.originator-tenant"],[v.RELATED,"tb.rulenode.originator-related"],[v.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(M||(M={}));var w,R=new Map([[M.CIRCLE,"tb.rulenode.perimeter-circle"],[M.POLYGON,"tb.rulenode.perimeter-polygon"]]);!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(w||(w={}));var D,O=new Map([[w.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[w.SECONDS,"tb.rulenode.time-unit-seconds"],[w.MINUTES,"tb.rulenode.time-unit-minutes"],[w.HOURS,"tb.rulenode.time-unit-hours"],[w.DAYS,"tb.rulenode.time-unit-days"]]);!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(D||(D={}));var K,B=new Map([[D.METER,"tb.rulenode.range-unit-meter"],[D.KILOMETER,"tb.rulenode.range-unit-kilometer"],[D.FOOT,"tb.rulenode.range-unit-foot"],[D.MILE,"tb.rulenode.range-unit-mile"],[D.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(K||(K={}));var G,U,j,H=new Map([[K.TITLE,"tb.rulenode.entity-details-title"],[K.COUNTRY,"tb.rulenode.entity-details-country"],[K.STATE,"tb.rulenode.entity-details-state"],[K.ZIP,"tb.rulenode.entity-details-zip"],[K.ADDRESS,"tb.rulenode.entity-details-address"],[K.ADDRESS2,"tb.rulenode.entity-details-address2"],[K.PHONE,"tb.rulenode.entity-details-phone"],[K.EMAIL,"tb.rulenode.entity-details-email"],[K.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(G||(G={})),function(e){e.ASC="ASC",e.DESC="DESC"}(U||(U={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(j||(j={}));var z,$=new Map([[j.STANDARD,"tb.rulenode.sqs-queue-standard"],[j.FIFO,"tb.rulenode.sqs-queue-fifo"]]),Q=["anonymous","basic","cert.PEM"],_=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),W=["sas","cert.PEM"],J=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(z||(z={}));var Y=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],Z=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]),X=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=R,n.rangeUnits=Object.keys(D),n.rangeUnitTranslationMap=B,n.timeUnits=Object.keys(w),n.timeUnitsTranslationMap=O,n}return y(r,e),r.prototype.configForm=function(){return this.geoActionConfigForm},r.prototype.onConfigurationSet=function(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[i.Validators.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterType").setValidators([]):this.geoActionConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoActionConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoActionConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.msgCountConfigForm},r.prototype.onConfigurationSet=function(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[i.Validators.required,i.Validators.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-msg-count-config",template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.rpcReplyConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rpc-reply-config",template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.saveToCustomTableConfigForm},r.prototype.onConfigurationSet=function(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[i.Validators.required]],fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-custom-table-config",template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n \n \n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ne=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.translate=r,o.injector=n,o.fb=a,o.propagateChange=null,o.valueChangeSubscription=null,o}var a;return y(r,e),a=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){this.ngControl=this.injector.get(i.NgControl),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))},r.prototype.keyValsFormArray=function(){return this.kvListFormGroup.get("keyVals")},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t,r,n=this;this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();var a=[];if(e)try{for(var o=C(Object.keys(e)),l=o.next();!l.done;l=o.next()){var s=l.value;Object.prototype.hasOwnProperty.call(e,s)&&a.push(this.fb.group({key:[s,[i.Validators.required]],value:[e[s],[i.Validators.required]]}))}}catch(e){t={error:e}}finally{try{l&&!l.done&&(r=o.return)&&r.call(o)}finally{if(t)throw t.error}}this.kvListFormGroup.setControl("keyVals",this.fb.array(a)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((function(){n.updateModel()}))},r.prototype.removeKeyVal=function(e){this.kvListFormGroup.get("keyVals").removeAt(e)},r.prototype.addKeyVal=function(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[i.Validators.required]],value:["",[i.Validators.required]]}))},r.prototype.validate=function(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}},r.prototype.updateModel=function(){var e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{var t={};e.forEach((function(e){t[e.key]=e.value})),this.propagateChange(t)}},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:t.Injector},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",String)],r.prototype,"requiredText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"keyText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"keyRequiredText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"valText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"valRequiredText",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=a=b([t.Component({selector:"tb-kv-map-config",template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n \n
\n \n
\n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return a})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return a})),multi:!0}],styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:rgba(0,0,0,.54);font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}"]}),h("design:paramtypes",[o.Store,n.TranslateService,t.Injector,i.FormBuilder])],r)}(a.PageComponent),ae=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n.propagateChange=null,n}var n;return y(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[i.Validators.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((function(t){e.deviceRelationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=b([t.Component({selector:"tb-device-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-type
\n \n \n
device.device-types
\n \n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.propagateChange=null,n}var n;return y(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((function(t){e.relationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=b([t.Component({selector:"tb-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),ie=function(e){function r(t,r,n,o){var i,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.truncate=n,s.fb=o,s.placeholder="tb.rulenode.message-type",s.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],s.messageTypes=[],s.messageTypesList=[],s.searchText="",s.propagateChange=function(e){},s.messageTypeConfigForm=s.fb.group({messageType:[null]});try{for(var u=C(Object.keys(a.MessageType)),d=u.next();!d.done;d=u.next()){var p=d.value;s.messageTypesList.push({name:a.messageTypeNames.get(a.MessageType[p]),value:p})}}catch(e){i={error:e}}finally{try{d&&!d.done&&(l=u.return)&&l.call(u)}finally{if(i)throw i.error}}return s}var l;return y(r,e),l=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.ngOnInit=function(){var e=this;this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(t){return e.fetchMessageTypes(t)})),f.share())},r.prototype.ngAfterViewInit=function(){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t=this;this.searchText="",this.messageTypes.length=0,e&&e.forEach((function(e){var r=t.messageTypesList.find((function(t){return t.value===e}));r?t.messageTypes.push({name:r.name,value:r.value}):t.messageTypes.push({name:e,value:e})}))},r.prototype.displayMessageTypeFn=function(e){return e?e.name:void 0},r.prototype.textIsNotEmpty=function(e){return!!(e&&null!=e&&e.length>0)},r.prototype.createMessageType=function(e,t){e.preventDefault(),this.transformMessageType(t)},r.prototype.add=function(e){this.transformMessageType(e.value)},r.prototype.fetchMessageTypes=function(e){if(this.searchText=e,this.searchText&&this.searchText.length){var t=this.searchText.toUpperCase();return c.of(this.messageTypesList.filter((function(e){return e.name.toUpperCase().includes(t)})))}return c.of(this.messageTypesList)},r.prototype.transformMessageType=function(e){if((e||"").trim()){var t=null,r=e.trim(),n=this.messageTypesList.find((function(e){return e.name===r}));(t=n?{name:n.name,value:n.value}:{name:r,value:r})&&this.addMessageType(t)}this.clear("")},r.prototype.remove=function(e){var t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())},r.prototype.selected=function(e){this.addMessageType(e.option.value),this.clear("")},r.prototype.addMessageType=function(e){-1===this.messageTypes.findIndex((function(t){return t.value===e.value}))&&(this.messageTypes.push(e),this.updateModel())},r.prototype.onFocus=function(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((function(){t.messageTypeInput.nativeElement.blur(),t.messageTypeInput.nativeElement.focus()}),0)},r.prototype.updateModel=function(){var e=this.messageTypes.map((function(e){return e.value}));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:a.TruncatePipe},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),b([t.Input(),h("design:type",String)],r.prototype,"label",void 0),b([t.Input(),h("design:type",Object)],r.prototype,"placeholder",void 0),b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.ViewChild("chipList",{static:!1}),h("design:type",d.MatChipList)],r.prototype,"chipList",void 0),b([t.ViewChild("messageTypeAutocomplete",{static:!1}),h("design:type",p.MatAutocomplete)],r.prototype,"matAutocomplete",void 0),b([t.ViewChild("messageTypeInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"messageTypeInput",void 0),r=l=b([t.Component({selector:"tb-message-types-config",template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return l})),multi:!0}]}),h("design:paramtypes",[o.Store,n.TranslateService,a.TruncatePipe,i.FormBuilder])],r)}(a.PageComponent),le=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.subscriptions=[],n.disableCertPemCredentials=!1,n.allCredentialsTypes=Q,n.credentialsTypeTranslationsMap=_,n.propagateChange=null,n}var n;return y(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.credentialsConfigFormGroup=this.fb.group({type:[null,[i.Validators.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(f.distinctUntilChanged()).subscribe((function(){e.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((function(){e.credentialsTypeChanged()})))},r.prototype.ngOnChanges=function(e){var t,r,n=this;try{for(var a=C(Object.keys(e)),o=a.next();!o.done;o=a.next()){var i=o.value,l=e[i];if(!l.firstChange&&l.currentValue!==l.previousValue)if(l.currentValue&&"disableCertPemCredentials"===i)"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((function(){n.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}catch(e){t={error:e}}finally{try{o&&!o.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}},r.prototype.ngOnDestroy=function(){this.subscriptions.forEach((function(e){return e.unsubscribe()}))},r.prototype.writeValue=function(e){s.isDefinedAndNotNull(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))},r.prototype.setDisabledState=function(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())},r.prototype.updateView=function(){var e=this.credentialsConfigFormGroup.value,t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.validate=function(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}},r.prototype.credentialsTypeChanged=function(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()},r.prototype.updateValidators=function(e){void 0===e&&(e=!1);var t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([i.Validators.required]),this.credentialsConfigFormGroup.get("password").setValidators([i.Validators.required]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(i.Validators.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})},r.prototype.requiredFilesSelected=function(e,t){return void 0===t&&(t=null),function(r){return t||(t=[Object.keys(r.controls)]),(null==r?void 0:r.controls)&&t.some((function(t){return t.every((function(t){return!e(r.controls[t])}))}))?null:{notAllRequiredFilesSelected:!0}}},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),b([t.Input(),h("design:type",Object)],r.prototype,"disableCertPemCredentials",void 0),r=n=b([t.Component({selector:"tb-credentials-config",template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n
\n
\n
\n
\n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),se=function(){function e(){}return e=b([t.NgModule({declarations:[ne,ae,oe,ie,le],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule],exports:[ne,ae,oe,ie,le]})],e)}(),me=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.unassignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-un-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ue=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.snsConfigForm},r.prototype.onConfigurationSet=function(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[i.Validators.required]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-sns-config",template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),de=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.sqsQueueType=j,n.sqsQueueTypes=Object.keys(j),n.sqsQueueTypeTranslationsMap=$,n}return y(r,e),r.prototype.configForm=function(){return this.sqsConfigForm},r.prototype.onConfigurationSet=function(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[i.Validators.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[i.Validators.required]],delaySeconds:[e?e.delaySeconds:null,[i.Validators.min(0),i.Validators.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-sqs-config",template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.pubSubConfigForm},r.prototype.onConfigurationSet=function(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[i.Validators.required]],topicName:[e?e.topicName:null,[i.Validators.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[i.Validators.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[i.Validators.required]],messageAttributes:[e?e.messageAttributes:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-pub-sub-config",template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.ackValues=["all","-1","0","1"],n.ToByteStandartCharsetTypesValues=Y,n.ToByteStandartCharsetTypeTranslationMap=Z,n}return y(r,e),r.prototype.configForm=function(){return this.kafkaConfigForm},r.prototype.onConfigurationSet=function(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],bootstrapServers:[e?e.bootstrapServers:null,[i.Validators.required]],retries:[e?e.retries:null,[i.Validators.min(0)]],batchSize:[e?e.batchSize:null,[i.Validators.min(0)]],linger:[e?e.linger:null,[i.Validators.min(0)]],bufferMemory:[e?e.bufferMemory:null,[i.Validators.min(0)]],acks:[e?e.acks:null,[i.Validators.required]],keySerializer:[e?e.keySerializer:null,[i.Validators.required]],valueSerializer:[e?e.valueSerializer:null,[i.Validators.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})},r.prototype.validatorTriggers=function(){return["addMetadataKeyValuesAsKafkaHeaders"]},r.prototype.updateValidators=function(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([i.Validators.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-kafka-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.mqttConfigForm},r.prototype.onConfigurationSet=function(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-mqtt-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n \n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],n}return y(r,e),r.prototype.configForm=function(){return this.rabbitMqConfigForm},r.prototype.onConfigurationSet=function(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[i.Validators.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[i.Validators.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rabbit-mq-config",template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ye=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.proxySchemes=["http","https"],n.httpRequestTypes=Object.keys(z),n}return y(r,e),r.prototype.configForm=function(){return this.restApiCallConfigForm},r.prototype.onConfigurationSet=function(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[i.Validators.required]],requestMethod:[e?e.requestMethod:null,[i.Validators.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[i.Validators.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})},r.prototype.validatorTriggers=function(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]},r.prototype.updateValidators=function(e){var t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,r=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,n=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;n&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(n?[i.Validators.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(n?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([i.Validators.min(0)])),r?this.restApiCallConfigForm.get("maxQueueSize").setValidators([i.Validators.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rest-api-call-config",template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n \n \n \n tb.rulenode.max-parallel-requests-count\n \n \n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.smtpProtocols=["smtp","smtps"],n.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"],n}return y(r,e),r.prototype.configForm=function(){return this.sendEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmtpSettings","enableProxy"]},r.prototype.updateValidators=function(e){var t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,r=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([i.Validators.required,i.Validators.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(r?[i.Validators.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(r?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-send-email-config",template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),he=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.serviceType=a.ServiceType.TB_RULE_ENGINE,n}return y(r,e),r.prototype.configForm=function(){return this.checkPointConfigForm},r.prototype.onConfigurationSet=function(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-check-point-config",template:'
\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allAzureIotHubCredentialsTypes=W,n.azureIotHubCredentialsTypeTranslationsMap=J,n}return y(r,e),r.prototype.configForm=function(){return this.azureIotHubConfigForm},r.prototype.onConfigurationSet=function(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[i.Validators.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[i.Validators.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})},r.prototype.prepareOutputConfig=function(e){var t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e},r.prototype.validatorTriggers=function(){return["credentials.type"]},r.prototype.updateValidators=function(e){var t=this.azureIotHubConfigForm.get("credentials"),r=t.get("type").value;switch(e&&t.reset({type:r},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),r){case"sas":t.get("sasKey").setValidators([i.Validators.required]);break;case"cert.PEM":t.get("privateKey").setValidators([i.Validators.required]),t.get("privateKeyFileName").setValidators([i.Validators.required]),t.get("cert").setValidators([i.Validators.required]),t.get("certFileName").setValidators([i.Validators.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-azure-iot-hub-config",template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.deviceProfile},r.prototype.onConfigurationSet=function(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,i.Validators.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,i.Validators.required]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-device-profile-config",template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.sendSmsConfigForm},r.prototype.onConfigurationSet=function(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[i.Validators.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[i.Validators.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmsSettings"]},r.prototype.updateValidators=function(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([i.Validators.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-send-sms-config",template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),xe=function(){function e(){}return e=b([t.NgModule({declarations:[x,T,q,S,I,k,N,V,E,A,L,X,ee,te,re,me,ue,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule,se],exports:[x,T,q,S,I,k,N,V,E,A,L,X,ee,te,re,me,ue,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe]})],e)}(),Te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.checkMessageConfigForm},r.prototype.onConfigurationSet=function(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})},r.prototype.validateConfig=function(){var e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0},r.prototype.removeMessageName=function(e){var t=this.checkMessageConfigForm.get("messageNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))},r.prototype.removeMetadataName=function(e){var t=this.checkMessageConfigForm.get("metadataNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))},r.prototype.addMessageName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("messageNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("messageNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.prototype.addMetadataName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("metadataNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("metadataNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-check-message-config",template:'
\n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),qe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.entitySearchDirection=Object.keys(a.EntitySearchDirection),n.entitySearchDirectionTranslationsMap=a.entitySearchDirectionTranslations,n}return y(r,e),r.prototype.configForm=function(){return this.checkRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],relationType:[e?e.relationType:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["checkForSingleEntity"]},r.prototype.updateValidators=function(e){var t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-check-relation-config",template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=R,n.rangeUnits=Object.keys(D),n.rangeUnitTranslationMap=B,n}return y(r,e),r.prototype.configForm=function(){return this.geoFilterConfigForm},r.prototype.onConfigurationSet=function(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterType").setValidators([]):this.geoFilterConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoFilterConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoFilterConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ie=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.messageTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-message-type-config",template:'
\n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allowedEntityTypes=[a.EntityType.DEVICE,a.EntityType.ASSET,a.EntityType.ENTITY_VIEW,a.EntityType.TENANT,a.EntityType.CUSTOMER,a.EntityType.USER,a.EntityType.DASHBOARD,a.EntityType.RULE_CHAIN,a.EntityType.RULE_NODE],n}return y(r,e),r.prototype.configForm=function(){return this.originatorTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-originator-type-config",template:'
\n \n \n \n
\n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ne=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-filter-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Ve=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.switchConfigForm},r.prototype.onConfigurationSet=function(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.switchConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-filter-node-switch-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Ee=function(e){function r(t,r,n){var o,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.fb=n,s.alarmStatusTranslationsMap=a.alarmStatusTranslations,s.alarmStatusList=[],s.searchText="",s.displayStatusFn=s.displayStatus.bind(s);try{for(var m=C(Object.keys(a.AlarmStatus)),u=m.next();!u.done;u=m.next()){var d=u.value;s.alarmStatusList.push(a.AlarmStatus[d])}}catch(e){o={error:e}}finally{try{u&&!u.done&&(l=m.return)&&l.call(m)}finally{if(o)throw o.error}}return s.statusFormControl=new i.FormControl(""),s.filteredAlarmStatus=s.statusFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return s.fetchAlarmStatus(e)})),f.share()),s}return y(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.alarmStatusConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[i.Validators.required]]})},r.prototype.displayStatus=function(e){return e?this.translate.instant(a.alarmStatusTranslations.get(e)):void 0},r.prototype.fetchAlarmStatus=function(e){var t=this,r=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){var n=this.searchText.toUpperCase();return c.of(r.filter((function(e){return t.translate.instant(a.alarmStatusTranslations.get(a.AlarmStatus[e])).toUpperCase().includes(n)})))}return c.of(r)},r.prototype.alarmStatusSelected=function(e){this.addAlarmStatus(e.option.value),this.clear("")},r.prototype.removeAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}},r.prototype.addAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))},r.prototype.getAlarmStatusList=function(){var e=this;return this.alarmStatusList.filter((function(t){return-1===e.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(t)}))},r.prototype.onAlarmStatusInputFocus=function(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.alarmStatusInput.nativeElement.blur(),t.alarmStatusInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},b([t.ViewChild("alarmStatusInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"alarmStatusInput",void 0),r=b([t.Component({selector:"tb-filter-node-check-alarm-status-config",template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n'}),h("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ae=function(){function e(){}return e=b([t.NgModule({declarations:[Te,qe,Se,Ie,ke,Ne,Ve,Ee],imports:[r.CommonModule,a.SharedModule,se],exports:[Te,qe,Se,Ie,ke,Ne,Ve,Ee]})],e)}(),Le=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.customerAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-customer-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Me=function(e){function r(t,r,n){var a,o,l=e.call(this,t)||this;l.store=t,l.translate=r,l.fb=n,l.entityDetailsTranslationsMap=H,l.entityDetailsList=[],l.searchText="",l.displayDetailsFn=l.displayDetails.bind(l);try{for(var s=C(Object.keys(K)),m=s.next();!m.done;m=s.next()){var u=m.value;l.entityDetailsList.push(K[u])}}catch(e){a={error:e}}finally{try{m&&!m.done&&(o=s.return)&&o.call(s)}finally{if(a)throw a.error}}return l.detailsFormControl=new i.FormControl(""),l.filteredEntityDetails=l.detailsFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return l.fetchEntityDetails(e)})),f.share()),l}return y(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.entityDetailsConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[i.Validators.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})},r.prototype.displayDetails=function(e){return e?this.translate.instant(H.get(e)):void 0},r.prototype.fetchEntityDetails=function(e){var t=this;if(this.searchText=e,this.searchText&&this.searchText.length){var r=this.searchText.toUpperCase();return c.of(this.entityDetailsList.filter((function(e){return t.translate.instant(H.get(K[e])).toUpperCase().includes(r)})))}return c.of(this.entityDetailsList)},r.prototype.detailsFieldSelected=function(e){this.addDetailsField(e.option.value),this.clear("")},r.prototype.removeDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}},r.prototype.addDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))},r.prototype.onEntityDetailsInputFocus=function(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.detailsInput.nativeElement.blur(),t.detailsInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},b([t.ViewChild("detailsInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"detailsInput",void 0),r=b([t.Component({selector:"tb-enrichment-node-entity-details-config",template:'
\n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-entity-details-matching\n
\n
\n
\n
\n
\n \n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
tb.rulenode.add-to-metadata-hint
\n
\n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}"]}),h("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.deviceAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[i.Validators.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.deviceAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.deviceAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.deviceAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.deviceAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-device-attributes-config",template:'
\n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),we=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.originatorAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.originatorAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.originatorAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.originatorAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.originatorAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-originator-attributes-config",template:'
\n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.originatorFieldsConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-originator-fields-config",template:'
\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),De=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n.fetchMode=G,n.fetchModes=Object.keys(G),n.samplingOrders=Object.keys(U),n.timeUnits=Object.keys(w),n.timeUnitsTranslationMap=O,n}return y(r,e),r.prototype.configForm=function(){return this.getTelemetryFromDatabaseConfigForm},r.prototype.onConfigurationSet=function(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],fetchMode:[e?e.fetchMode:null,[i.Validators.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchMode","useMetadataIntervalPatterns"]},r.prototype.updateValidators=function(e){var t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,r=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===G.ALL?(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([i.Validators.required,i.Validators.min(2),i.Validators.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),r?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([i.Validators.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})},r.prototype.removeKey=function(e,t){var r=this.getTelemetryFromDatabaseConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.getTelemetryFromDatabaseConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-get-telemetry-from-database",template:'
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
\n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
\n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-interval-patterns-hint
\n
\n
\n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.relatedAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[i.Validators.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-related-attributes-config",template:'
\n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.tenantAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-tenant-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.calculateDeltaConfigForm},r.prototype.onConfigurationSet=function(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e?e.inputValueKey:null,[i.Validators.required]],outputValueKey:[e?e.outputValueKey:null,[i.Validators.required]],useCache:[e?e.useCache:null,[]],addPeriodBetweenMsgs:[!!e&&e.addPeriodBetweenMsgs,[]],periodValueKey:[e?e.periodValueKey:null,[]],round:[e?e.round:null,[i.Validators.min(0),i.Validators.max(15)]],tellFailureIfInputValueKeyIsAbsent:[e?e.tellFailureIfInputValueKeyIsAbsent:null,[]],tellFailureIfDeltaIsNegative:[e?e.tellFailureIfDeltaIsNegative:null,[]]})},r.prototype.updateValidators=function(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([i.Validators.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})},r.prototype.validatorTriggers=function(){return["addPeriodBetweenMsgs"]},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-calculate-delta-config",template:'
\n
\n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-input-value-key-is-absent\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ge=function(){function e(){}return e=b([t.NgModule({declarations:[Le,Me,Pe,we,Re,De,Oe,Ke,Be],imports:[r.CommonModule,a.SharedModule,se],exports:[Le,Me,Pe,we,Re,De,Oe,Ke,Be]})],e)}(),Ue=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.originatorSource=v,n.originatorSources=Object.keys(v),n.originatorSourceTranslationMap=P,n}return y(r,e),r.prototype.configForm=function(){return this.changeOriginatorConfigForm},r.prototype.onConfigurationSet=function(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[i.Validators.required]],relationsQuery:[e?e.relationsQuery:null,[]]})},r.prototype.validatorTriggers=function(){return["originatorSource"]},r.prototype.updateValidators=function(e){var t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===v.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([i.Validators.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-transformation-node-change-originator-config",template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),je=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-transformation-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),He=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.toEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[i.Validators.required]],toTemplate:[e?e.toTemplate:null,[i.Validators.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[i.Validators.required]],bodyTemplate:[e?e.bodyTemplate:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-transformation-node-to-email-config",template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ze=function(){function e(){}return e=b([t.NgModule({declarations:[Ue,je,He],imports:[r.CommonModule,a.SharedModule,se],exports:[Ue,je,He]})],e)}(),$e=function(){function e(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-name-pattern-hint":"Name pattern, use ${metaKeyName} to substitute variables from metadata","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-type-pattern-hint":"Type pattern, use ${metaKeyName} to substitute variables from metadata","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-name-pattern-hint":"Customer name pattern, use ${metaKeyName} to substitute variables from metadata","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","client-attributes-hint":"Client attributes, use ${metaKeyName} to substitute variables from metadata","shared-attributes":"Shared attributes","shared-attributes-hint":"Shared attributes, use ${metaKeyName} to substitute variables from metadata","server-attributes":"Server attributes","server-attributes-hint":"Server attributes, use ${metaKeyName} to substitute variables from metadata","notify-device":"Notify Device","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","latest-timeseries":"Latest timeseries","latest-timeseries-hint":"Latest timeseries, use ${metaKeyName} to substitute variables from metadata","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-hint":"Relation type pattern, use ${metaKeyName} to substitute variables from metadata","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use metadata period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds metadata pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","period-in-seconds-pattern-hint":"Period in seconds pattern, use ${metaKeyName} to substitute variables from metadata","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","from-template-hint":"From address template, use ${metaKeyName} to substitute variables from metadata","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":"Comma separated address list, use ${metaKeyName} to substitute variables from metadata","cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","subject-template-hint":"Mail subject template, use ${metaKeyName} to substitute variables from metadata","body-template":"Body Template","body-template-required":"Body Template is required","body-template-hint":"Mail body template, use ${metaKeyName} to substitute variables from metadata","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","endpoint-url-pattern-hint":"HTTP URL address pattern, use ${metaKeyName} to substitute variables from metadata","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":"Use ${metaKeyName} in header/value fields to substitute variables from metadata",header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required","mqtt-topic-pattern-hint":"MQTT topic pattern, use ${metaKeyName} to substitute variables from metadata",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","topic-arn-pattern-hint":"Topic ARN pattern, use ${metaKeyName} to substitute variables from metadata","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","queue-url-pattern-hint":"Queue URL pattern, use ${metaKeyName} to substitute variables from metadata","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":"Use ${metaKeyName} in name/value fields to substitute variables from metadata","connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file *","private-key":"Client private key file *",cert:"Client certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use metadata interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","start-interval-pattern-hint":"Start interval pattern, use ${metaKeyName} to substitute variables from metadata","end-interval-pattern-hint":"End interval pattern, use ${metaKeyName} to substitute variables from metadata","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":"Comma separated Phone Numbers, use ${metaKeyName} to substitute variables from metadata","sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","sms-message-template-hint":"SMS message template, use ${metaKeyName} to substitute variables from metadata","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-zip":"Zip","entity-details-address":"Address","entity-details-address2":"Address2","entity-details-additional_info":"Additional Info","entity-details-phone":"Phone","entity-details-email":"Email","add-to-metadata":"Add selected details to message metadata","add-to-metadata-hint":"If selected, adds the selected details keys to the message metadata instead of message data.","entity-details-list-empty":"No entity details selected.","no-entity-details-matching":"No entity details matching were found.","custom-table-name":"Custom table name","custom-table-name-required":"Table Name is required","custom-table-hint":"You should enter the table name without prefix 'cs_tb_'.","message-field":"Message field","message-field-required":"Message field is required.","table-col":"Table column","table-col-required":"Table column is required.","latitude-key-name":"Latitude key name","longitude-key-name":"Longitude key name","latitude-key-name-required":"Latitude key name is required.","longitude-key-name-required":"Longitude key name is required.","fetch-perimeter-info-from-message-metadata":"Fetch perimeter information from message metadata","perimeter-circle":"Circle","perimeter-polygon":"Polygon","perimeter-type":"Perimeter type","circle-center-latitude":"Center latitude","circle-center-latitude-required":"Center latitude is required.","circle-center-longitude":"Center longitude","circle-center-longitude-required":"Center longitude is required.","range-unit-meter":"Meter","range-unit-kilometer":"Kilometer","range-unit-foot":"Foot","range-unit-mile":"Mile","range-unit-nautical-mile":"Nautical mile","range-units":"Range units",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].","min-inside-duration":"Minimal inside duration","min-inside-duration-value-required":"Minimal inside duration is required","min-inside-duration-time-unit":"Minimal inside duration time unit","min-outside-duration":"Minimal outside duration","min-outside-duration-value-required":"Minimal outside duration is required","min-outside-duration-time-unit":"Minimal outside duration time unit","tell-failure-if-absent":"Tell Failure","tell-failure-if-absent-hint":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"get-latest-value-with-ts":"Fetch Latest telemetry with Timestamp","get-latest-value-with-ts-hint":'If selected, latest telemetry values will be added to the outbound message metadata with timestamp, e.g: "temp": "{\\"ts\\":1574329385897,\\"value\\":42}"',"use-redis-queue":"Use redis queue for message persistence","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required.","output-value-key":"Output value key","output-value-key-required":"Output value key is required.",round:"Decimals","round-range":"Decimals should be in a range from 0 to 15.","use-cache":"Use cache for latest value","tell-failure-if-input-value-key-is-absent":"Tell Failure if input value key is absent","tell-failure-if-delta-is-negative":"Tell Failure if delta is negative","add-period-between-msgs":"Add period between messages","period-value-key":"Period value key","period-key-required":"Period value key is required."},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"}}},!0)}(e)}return e.ctorParameters=function(){return[{type:n.TranslateService}]},e=b([t.NgModule({declarations:[F],imports:[r.CommonModule,a.SharedModule],exports:[xe,Ae,Ge,ze,F]}),h("design:paramtypes",[n.TranslateService])],e)}();e.RuleNodeCoreConfigModule=$e,e.ɵa=F,e.ɵb=xe,e.ɵba=he,e.ɵbb=Ce,e.ɵbc=ve,e.ɵbd=Fe,e.ɵbe=se,e.ɵbf=ne,e.ɵbg=ae,e.ɵbh=oe,e.ɵbi=ie,e.ɵbj=le,e.ɵbk=Ae,e.ɵbl=Te,e.ɵbm=qe,e.ɵbn=Se,e.ɵbo=Ie,e.ɵbp=ke,e.ɵbq=Ne,e.ɵbr=Ve,e.ɵbs=Ee,e.ɵbt=Ge,e.ɵbu=Le,e.ɵbv=Me,e.ɵbw=Pe,e.ɵbx=we,e.ɵby=Re,e.ɵbz=De,e.ɵc=x,e.ɵca=Oe,e.ɵcb=Ke,e.ɵcc=Be,e.ɵcd=ze,e.ɵce=Ue,e.ɵcf=je,e.ɵcg=He,e.ɵd=T,e.ɵe=q,e.ɵf=S,e.ɵg=I,e.ɵh=k,e.ɵi=N,e.ɵj=V,e.ɵk=E,e.ɵl=A,e.ɵm=L,e.ɵn=X,e.ɵo=ee,e.ɵp=te,e.ɵq=re,e.ɵr=me,e.ɵs=ue,e.ɵt=de,e.ɵu=pe,e.ɵv=ce,e.ɵw=fe,e.ɵx=ge,e.ɵy=ye,e.ɵz=be,Object.defineProperty(e,"__esModule",{value:!0})})); //# sourceMappingURL=rulenode-core-config.umd.min.js.map \ No newline at end of file From 4c87b36a9230a6a96c0363a4ae0d8de2c2d0b450 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 3 Feb 2021 17:58:12 +0200 Subject: [PATCH 113/249] Minor fixes --- .../thingsboard/server/controller/DashboardController.java | 4 ++-- ui-ngx/src/app/core/services/menu.service.ts | 2 ++ .../dashboard-page/dashboard-page.component.html | 6 +++--- .../components/dashboard-page/dashboard-page.component.ts | 7 +++++-- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java index c780dde8a9..f5b350d861 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java @@ -524,7 +524,7 @@ public class DashboardController extends BaseController { JsonNode additionalInfo = tenant.getAdditionalInfo(); DashboardId dashboardId = null; boolean hideDashboardToolbar = true; - if (additionalInfo != null && additionalInfo.has(HOME_DASHBOARD_ID)) { + if (additionalInfo != null && additionalInfo.has(HOME_DASHBOARD_ID) && !additionalInfo.get(HOME_DASHBOARD_ID).isNull()) { String strDashboardId = additionalInfo.get(HOME_DASHBOARD_ID).asText(); dashboardId = new DashboardId(toUUID(strDashboardId)); if (additionalInfo.has(HOME_DASHBOARD_HIDE_TOOLBAR)) { @@ -566,7 +566,7 @@ public class DashboardController extends BaseController { private HomeDashboard extractHomeDashboardFromAdditionalInfo(JsonNode additionalInfo) { try { - if (additionalInfo != null && additionalInfo.has(HOME_DASHBOARD_ID)) { + if (additionalInfo != null && additionalInfo.has(HOME_DASHBOARD_ID) && !additionalInfo.get(HOME_DASHBOARD_ID).isNull()) { String strDashboardId = additionalInfo.get(HOME_DASHBOARD_ID).asText(); DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); Dashboard dashboard = checkDashboardId(dashboardId, Operation.READ); diff --git a/ui-ngx/src/app/core/services/menu.service.ts b/ui-ngx/src/app/core/services/menu.service.ts index 735fd6bead..d1fffa3fde 100644 --- a/ui-ngx/src/app/core/services/menu.service.ts +++ b/ui-ngx/src/app/core/services/menu.service.ts @@ -223,6 +223,7 @@ export class MenuService { name: 'home.home', type: 'link', path: '/home', + notExact: true, icon: 'home' }, { @@ -409,6 +410,7 @@ export class MenuService { name: 'home.home', type: 'link', path: '/home', + notExact: true, icon: 'home' }, { diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html index 97f5071955..5ba7f2f01c 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html @@ -49,7 +49,7 @@ {{ isFullscreen ? 'fullscreen_exit' : 'fullscreen' }} - - { if (this.embedded) { - data.dashboard = this.dashboard; + data.dashboard = this.dashboardUtils.validateAndUpdateDashboard(this.dashboard); + data.currentDashboardId = this.dashboard.id ? this.dashboard.id.id : null; data.widgetEditMode = false; data.singlePageMode = false; + } else { + data.currentDashboardId = this.route.snapshot.params.dashboardId; } this.init(data); this.runChangeDetection(); @@ -286,7 +289,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC this.reset(); - this.currentDashboardId = this.route.snapshot.params.dashboardId; + this.currentDashboardId = data.currentDashboardId; if (this.route.snapshot.params.customerId) { this.currentCustomerId = this.route.snapshot.params.customerId; From 58c12d1212c4a1276c7b3899ef27a85b75895752 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Thu, 4 Feb 2021 13:06:22 +0200 Subject: [PATCH 114/249] Fixed merge additional info at updated entity --- .../home/components/entity/entity-details-panel.component.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/entity/entity-details-panel.component.ts b/ui-ngx/src/app/modules/home/components/entity/entity-details-panel.component.ts index 0af4689a18..1efcc9211e 100644 --- a/ui-ngx/src/app/modules/home/components/entity/entity-details-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/entity/entity-details-panel.component.ts @@ -44,7 +44,7 @@ import { EntityAction } from '@home/models/entity/entity-component.models'; import { Subscription } from 'rxjs'; import { MatTab, MatTabGroup } from '@angular/material/tabs'; import { EntityTabsComponent } from '@home/components/entity/entity-tabs.component'; -import { deepClone } from '@core/utils'; +import { deepClone, mergeDeep } from '@core/utils'; @Component({ selector: 'tb-entity-details-panel', @@ -280,7 +280,7 @@ export class EntityDetailsPanelComponent extends PageComponent implements OnInit saveEntity() { if (this.detailsForm.valid) { - const editingEntity = {...this.editingEntity, ...this.entityComponent.entityFormValue()}; + const editingEntity = mergeDeep(this.editingEntity, this.entityComponent.entityFormValue()); this.entitiesTableConfig.saveEntity(editingEntity).subscribe( (entity) => { this.entity = entity; From caa5c43288f38be68a70207c718018eec0bc0045 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 4 Feb 2021 14:58:06 +0200 Subject: [PATCH 115/249] added ability to use pattern to substitute variables from data in rule nodes --- .../rule/engine/api/util/TbNodeUtils.java | 54 +++++++++++++++++-- .../action/TbAbstractCustomerActionNode.java | 2 +- .../action/TbAbstractRelationActionNode.java | 2 +- .../rule/engine/action/TbClearAlarmNode.java | 2 +- .../rule/engine/action/TbCreateAlarmNode.java | 4 +- .../rule/engine/aws/sns/TbSnsNode.java | 2 +- .../rule/engine/aws/sqs/TbSqsNode.java | 6 +-- .../rule/engine/delay/TbMsgDelayNode.java | 4 +- .../rule/engine/gcp/pubsub/TbPubSubNode.java | 4 +- .../rule/engine/kafka/TbKafkaNode.java | 2 +- .../rule/engine/mail/TbMsgToEmailNode.java | 16 +++--- .../metadata/TbAbstractGetAttributesNode.java | 8 +-- .../engine/metadata/TbGetTelemetryNode.java | 8 +-- .../rule/engine/mqtt/TbMqttNode.java | 2 +- .../rule/engine/rabbitmq/TbRabbitMqNode.java | 4 +- .../rule/engine/rest/TbHttpClient.java | 8 +-- .../rule/engine/sms/TbSendSmsNode.java | 4 +- 17 files changed, 89 insertions(+), 43 deletions(-) diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/util/TbNodeUtils.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/util/TbNodeUtils.java index 8804320295..475488847a 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/util/TbNodeUtils.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/util/TbNodeUtils.java @@ -16,15 +16,20 @@ package org.thingsboard.rule.engine.api.util; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.lang3.StringUtils; import org.springframework.util.CollectionUtils; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; /** @@ -34,8 +39,11 @@ public class TbNodeUtils { private static final ObjectMapper mapper = new ObjectMapper(); - private static final String VARIABLE_TEMPLATE = "${%s}"; + private static final String METADATA_VARIABLE_TEMPLATE = "${%s}"; + private static final Pattern DATA_PATTERN = Pattern.compile("(\\$\\[)(.*?)(\\])"); + + private static final String DATA_VARIABLE_TEMPLATE = "$[%s]"; public static T convert(TbNodeConfiguration configuration, Class clazz) throws TbNodeException { try { @@ -45,6 +53,44 @@ public class TbNodeUtils { } } + public static List processPatterns(List patterns, TbMsg tbMsg) { + if (!CollectionUtils.isEmpty(patterns)) { + return patterns.stream().map(p -> processPattern(p, tbMsg)).collect(Collectors.toList()); + } + return Collections.emptyList(); + } + + public static String processPattern(String pattern, TbMsg tbMsg) { + try { + String result = processPattern(pattern, tbMsg.getMetaData()); + JsonNode json = mapper.readTree(tbMsg.getData()); + if (json.isObject()) { + Matcher matcher = DATA_PATTERN.matcher(result); + + while (matcher.find()) { + String group = matcher.group(2); + String[] keys = group.split("\\."); + JsonNode jsonNode = json; + for (String key : keys) { + if (StringUtils.isNotEmpty(key) && jsonNode != null) { + jsonNode = jsonNode.get(key); + } else { + jsonNode = null; + break; + } + } + + if (jsonNode != null && !jsonNode.isObject() && !jsonNode.isArray()) { + result = result.replace(String.format(DATA_VARIABLE_TEMPLATE, group), jsonNode.asText()); + } + } + } + return result; + } catch (Exception e) { + throw new RuntimeException("Failed to process pattern!", e); + } + } + public static List processPatterns(List patterns, TbMsgMetaData metaData) { if (!CollectionUtils.isEmpty(patterns)) { return patterns.stream().map(p -> processPattern(p, metaData)).collect(Collectors.toList()); @@ -53,15 +99,15 @@ public class TbNodeUtils { } public static String processPattern(String pattern, TbMsgMetaData metaData) { - String result = new String(pattern); - for (Map.Entry keyVal : metaData.values().entrySet()) { + String result = pattern; + for (Map.Entry keyVal : metaData.values().entrySet()) { result = processVar(result, keyVal.getKey(), keyVal.getValue()); } return result; } private static String processVar(String pattern, String key, String val) { - String varPattern = String.format(VARIABLE_TEMPLATE, key); + String varPattern = String.format(METADATA_VARIABLE_TEMPLATE, key); return pattern.replace(varPattern, val); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractCustomerActionNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractCustomerActionNode.java index 482e5261f0..b47235572b 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractCustomerActionNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractCustomerActionNode.java @@ -79,7 +79,7 @@ public abstract class TbAbstractCustomerActionNode getCustomer(TbContext ctx, TbMsg msg) { - String customerTitle = TbNodeUtils.processPattern(this.config.getCustomerNamePattern(), msg.getMetaData()); + String customerTitle = TbNodeUtils.processPattern(this.config.getCustomerNamePattern(), msg); CustomerKey key = new CustomerKey(customerTitle); return ctx.getDbCallbackExecutor().executeAsync(() -> { Optional customerId = customerIdCache.get(key); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractRelationActionNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractRelationActionNode.java index 66a8f28e87..307a863938 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractRelationActionNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractRelationActionNode.java @@ -140,7 +140,7 @@ public abstract class TbAbstractRelationActionNode processAlarm(TbContext ctx, TbMsg msg) { - String alarmType = TbNodeUtils.processPattern(this.config.getAlarmType(), msg.getMetaData()); + String alarmType = TbNodeUtils.processPattern(this.config.getAlarmType(), msg); ListenableFuture alarmFuture; if (msg.getOriginator().getEntityType().equals(EntityType.ALARM)) { alarmFuture = ctx.getAlarmService().findAlarmByIdAsync(ctx.getTenantId(), new AlarmId(msg.getOriginator().getId())); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNode.java index dcae930fbd..c941d6ca92 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNode.java @@ -70,7 +70,7 @@ public class TbCreateAlarmNode extends TbAbstractAlarmNode messageAttributes = new HashMap<>(); this.config.getMessageAttributes().forEach((k,v) -> { - String name = TbNodeUtils.processPattern(k, msg.getMetaData()); - String val = TbNodeUtils.processPattern(v, msg.getMetaData()); + String name = TbNodeUtils.processPattern(k, msg); + String val = TbNodeUtils.processPattern(v, msg); messageAttributes.put(name, new MessageAttributeValue().withDataType("String").withStringValue(val)); }); sendMsgRequest.setMessageAttributes(messageAttributes); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java index d72c56981e..9192f0a55f 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java @@ -84,7 +84,7 @@ public class TbMsgDelayNode implements TbNode { int periodInSeconds; if (config.isUseMetadataPeriodInSecondsPatterns()) { if (isParsable(msg, config.getPeriodInSecondsPattern())) { - periodInSeconds = Integer.parseInt(TbNodeUtils.processPattern(config.getPeriodInSecondsPattern(), msg.getMetaData())); + periodInSeconds = Integer.parseInt(TbNodeUtils.processPattern(config.getPeriodInSecondsPattern(), msg)); } else { throw new RuntimeException("Can't parse period in seconds from metadata using pattern: " + config.getPeriodInSecondsPattern()); } @@ -95,7 +95,7 @@ public class TbMsgDelayNode implements TbNode { } private boolean isParsable(TbMsg msg, String pattern) { - return NumberUtils.isParsable(TbNodeUtils.processPattern(pattern, msg.getMetaData())); + return NumberUtils.isParsable(TbNodeUtils.processPattern(pattern, msg)); } @Override diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/gcp/pubsub/TbPubSubNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/gcp/pubsub/TbPubSubNode.java index c04de9e070..17c49adfc7 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/gcp/pubsub/TbPubSubNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/gcp/pubsub/TbPubSubNode.java @@ -91,8 +91,8 @@ public class TbPubSubNode implements TbNode { PubsubMessage.Builder pubsubMessageBuilder = PubsubMessage.newBuilder(); pubsubMessageBuilder.setData(data); this.config.getMessageAttributes().forEach((k, v) -> { - String name = TbNodeUtils.processPattern(k, msg.getMetaData()); - String val = TbNodeUtils.processPattern(v, msg.getMetaData()); + String name = TbNodeUtils.processPattern(k, msg); + String val = TbNodeUtils.processPattern(v, msg); pubsubMessageBuilder.putAttributes(name, val); }); ApiFuture messageIdFuture = this.pubSubClient.publish(pubsubMessageBuilder.build()); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java index 89cc747811..acc86b1e62 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java @@ -94,7 +94,7 @@ public class TbKafkaNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) { - String topic = TbNodeUtils.processPattern(config.getTopicPattern(), msg.getMetaData()); + String topic = TbNodeUtils.processPattern(config.getTopicPattern(), msg); try { ctx.getExternalCallExecutor().executeAsync(() -> { publish(ctx, msg, topic); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNode.java index 854c89e720..8372ebdd10 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNode.java @@ -72,18 +72,18 @@ public class TbMsgToEmailNode implements TbNode { private EmailPojo convert(TbMsg msg) throws IOException { EmailPojo.EmailPojoBuilder builder = EmailPojo.builder(); - builder.from(fromTemplate(this.config.getFromTemplate(), msg.getMetaData())); - builder.to(fromTemplate(this.config.getToTemplate(), msg.getMetaData())); - builder.cc(fromTemplate(this.config.getCcTemplate(), msg.getMetaData())); - builder.bcc(fromTemplate(this.config.getBccTemplate(), msg.getMetaData())); - builder.subject(fromTemplate(this.config.getSubjectTemplate(), msg.getMetaData())); - builder.body(fromTemplate(this.config.getBodyTemplate(), msg.getMetaData())); + builder.from(fromTemplate(this.config.getFromTemplate(), msg)); + builder.to(fromTemplate(this.config.getToTemplate(), msg)); + builder.cc(fromTemplate(this.config.getCcTemplate(), msg)); + builder.bcc(fromTemplate(this.config.getBccTemplate(), msg)); + builder.subject(fromTemplate(this.config.getSubjectTemplate(), msg)); + builder.body(fromTemplate(this.config.getBodyTemplate(), msg)); return builder.build(); } - private String fromTemplate(String template, TbMsgMetaData metaData) { + private String fromTemplate(String template, TbMsg msg) { if (!StringUtils.isEmpty(template)) { - return TbNodeUtils.processPattern(template, metaData); + return TbNodeUtils.processPattern(template, msg); } else { return null; } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java index 5788b2e086..1b0f4c95ef 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java @@ -92,10 +92,10 @@ public abstract class TbAbstractGetAttributesNode> failuresMap = new ConcurrentHashMap<>(); ListenableFuture> allFutures = Futures.allAsList( - putLatestTelemetry(ctx, entityId, msg, LATEST_TS, TbNodeUtils.processPatterns(config.getLatestTsKeyNames(), msg.getMetaData()), failuresMap), - putAttrAsync(ctx, entityId, msg, CLIENT_SCOPE, TbNodeUtils.processPatterns(config.getClientAttributeNames(), msg.getMetaData()), failuresMap, "cs_"), - putAttrAsync(ctx, entityId, msg, SHARED_SCOPE, TbNodeUtils.processPatterns(config.getSharedAttributeNames(), msg.getMetaData()), failuresMap, "shared_"), - putAttrAsync(ctx, entityId, msg, SERVER_SCOPE, TbNodeUtils.processPatterns(config.getServerAttributeNames(), msg.getMetaData()), failuresMap, "ss_") + putLatestTelemetry(ctx, entityId, msg, LATEST_TS, TbNodeUtils.processPatterns(config.getLatestTsKeyNames(), msg), failuresMap), + putAttrAsync(ctx, entityId, msg, CLIENT_SCOPE, TbNodeUtils.processPatterns(config.getClientAttributeNames(), msg), failuresMap, "cs_"), + putAttrAsync(ctx, entityId, msg, SHARED_SCOPE, TbNodeUtils.processPatterns(config.getSharedAttributeNames(), msg), failuresMap, "shared_"), + putAttrAsync(ctx, entityId, msg, SERVER_SCOPE, TbNodeUtils.processPatterns(config.getServerAttributeNames(), msg), failuresMap, "ss_") ); withCallback(allFutures, i -> { if (!failuresMap.isEmpty()) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java index bb5ffee78d..1174ad6c0c 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java @@ -103,7 +103,7 @@ public class TbGetTelemetryNode implements TbNode { if (config.isUseMetadataIntervalPatterns()) { checkMetadataKeyPatterns(msg); } - List keys = TbNodeUtils.processPatterns(tsKeyNames, msg.getMetaData()); + List keys = TbNodeUtils.processPatterns(tsKeyNames, msg); ListenableFuture> list = ctx.getTimeseriesService().findAll(ctx.getTenantId(), msg.getOriginator(), buildQueries(msg, keys)); DonAsynchron.withCallback(list, data -> { process(data, msg, keys); @@ -197,10 +197,10 @@ public class TbGetTelemetryNode implements TbNode { Interval interval = new Interval(); if (config.isUseMetadataIntervalPatterns()) { if (isParsable(msg, config.getStartIntervalPattern())) { - interval.setStartTs(Long.parseLong(TbNodeUtils.processPattern(config.getStartIntervalPattern(), msg.getMetaData()))); + interval.setStartTs(Long.parseLong(TbNodeUtils.processPattern(config.getStartIntervalPattern(), msg))); } if (isParsable(msg, config.getEndIntervalPattern())) { - interval.setEndTs(Long.parseLong(TbNodeUtils.processPattern(config.getEndIntervalPattern(), msg.getMetaData()))); + interval.setEndTs(Long.parseLong(TbNodeUtils.processPattern(config.getEndIntervalPattern(), msg))); } } else { long ts = System.currentTimeMillis(); @@ -211,7 +211,7 @@ public class TbGetTelemetryNode implements TbNode { } private boolean isParsable(TbMsg msg, String pattern) { - return NumberUtils.isParsable(TbNodeUtils.processPattern(pattern, msg.getMetaData())); + return NumberUtils.isParsable(TbNodeUtils.processPattern(pattern, msg)); } private void checkMetadataKeyPatterns(TbMsg msg) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java index 2ecf770e19..4c732e0d97 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java @@ -76,7 +76,7 @@ public class TbMqttNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) { - String topic = TbNodeUtils.processPattern(this.mqttNodeConfiguration.getTopicPattern(), msg.getMetaData()); + String topic = TbNodeUtils.processPattern(this.mqttNodeConfiguration.getTopicPattern(), msg); this.mqttClient.publish(topic, Unpooled.wrappedBuffer(msg.getData().getBytes(UTF8)), MqttQoS.AT_LEAST_ONCE) .addListener(future -> { if (future.isSuccess()) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rabbitmq/TbRabbitMqNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rabbitmq/TbRabbitMqNode.java index 898334781e..f481c875a9 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rabbitmq/TbRabbitMqNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rabbitmq/TbRabbitMqNode.java @@ -90,11 +90,11 @@ public class TbRabbitMqNode implements TbNode { private TbMsg publishMessage(TbContext ctx, TbMsg msg) throws Exception { String exchangeName = ""; if (!StringUtils.isEmpty(this.config.getExchangeNamePattern())) { - exchangeName = TbNodeUtils.processPattern(this.config.getExchangeNamePattern(), msg.getMetaData()); + exchangeName = TbNodeUtils.processPattern(this.config.getExchangeNamePattern(), msg); } String routingKey = ""; if (!StringUtils.isEmpty(this.config.getRoutingKeyPattern())) { - routingKey = TbNodeUtils.processPattern(this.config.getRoutingKeyPattern(), msg.getMetaData()); + routingKey = TbNodeUtils.processPattern(this.config.getRoutingKeyPattern(), msg); } AMQP.BasicProperties properties = null; if (!StringUtils.isEmpty(this.config.getMessageProperties())) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java index 17dc6b5bce..bbe1bccd0d 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java @@ -172,8 +172,8 @@ public class TbHttpClient { } public void processMessage(TbContext ctx, TbMsg msg) { - String endpointUrl = TbNodeUtils.processPattern(config.getRestEndpointUrlPattern(), msg.getMetaData()); - HttpHeaders headers = prepareHeaders(msg.getMetaData()); + String endpointUrl = TbNodeUtils.processPattern(config.getRestEndpointUrlPattern(), msg); + HttpHeaders headers = prepareHeaders(msg); HttpMethod method = HttpMethod.valueOf(config.getRequestMethod()); HttpEntity entity = new HttpEntity<>(msg.getData(), headers); @@ -232,9 +232,9 @@ public class TbHttpClient { return ctx.transformMsg(origMsg, origMsg.getType(), origMsg.getOriginator(), metaData, origMsg.getData()); } - private HttpHeaders prepareHeaders(TbMsgMetaData metaData) { + private HttpHeaders prepareHeaders(TbMsg msg) { HttpHeaders headers = new HttpHeaders(); - config.getHeaders().forEach((k, v) -> headers.add(TbNodeUtils.processPattern(k, metaData), TbNodeUtils.processPattern(v, metaData))); + config.getHeaders().forEach((k, v) -> headers.add(TbNodeUtils.processPattern(k, msg), TbNodeUtils.processPattern(v, msg))); ClientCredentials credentials = config.getCredentials(); if (CredentialsType.BASIC == credentials.getType()) { BasicCredentials basicCredentials = (BasicCredentials) credentials; diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/sms/TbSendSmsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/sms/TbSendSmsNode.java index 0061ff1cf4..df75afe086 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/sms/TbSendSmsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/sms/TbSendSmsNode.java @@ -72,8 +72,8 @@ public class TbSendSmsNode implements TbNode { } private void sendSms(TbContext ctx, TbMsg msg) throws Exception { - String numbersTo = TbNodeUtils.processPattern(this.config.getNumbersToTemplate(), msg.getMetaData()); - String message = TbNodeUtils.processPattern(this.config.getSmsMessageTemplate(), msg.getMetaData()); + String numbersTo = TbNodeUtils.processPattern(this.config.getNumbersToTemplate(), msg); + String message = TbNodeUtils.processPattern(this.config.getSmsMessageTemplate(), msg); String[] numbersToList = numbersTo.split(","); if (this.config.isUseSystemSmsSettings()) { ctx.getSmsService().sendSms(ctx.getTenantId(), numbersToList, message); From 22e577112096c009316c0cbdab317290935e4a65 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 4 Feb 2021 19:31:20 +0200 Subject: [PATCH 116/249] JDK 11 Support --- application/pom.xml | 2 +- .../actors/ruleChain/DefaultTbContext.java | 5 - .../RuleNodeActorMessageProcessor.java | 2 +- ...tomOAuth2AuthorizationRequestResolver.java | 1 + .../ThingsboardSecurityConfiguration.java | 2 +- .../server/controller/BaseController.java | 5 + .../controller/EntityViewController.java | 2 +- .../AnnotationComponentDiscoveryService.java | 5 +- .../device/DeviceProvisionServiceImpl.java | 2 +- .../install/cql/CassandraDbHelper.java | 8 +- .../install/migrate/CassandraToSqlColumn.java | 3 +- .../update/DefaultDataUpdateService.java | 2 +- .../query/DefaultEntityQueryService.java | 2 +- .../AbstractNashornJsInvokeService.java | 6 +- .../auth/jwt/SkipPathRequestMatcher.java | 2 +- .../security/model/token/JwtTokenFactory.java | 2 + .../permission/CustomerUserPermissions.java | 3 + .../DefaultAccessControlService.java | 1 + .../permission/TenantAdminPermissions.java | 1 + .../system/DefaultSystemSecurityService.java | 13 +- ...efaultTbEntityDataSubscriptionService.java | 1 + .../DefaultTbLocalSubscriptionService.java | 2 + .../subscription/TbAbstractDataSubCtx.java | 2 + .../cmd/v2/AlarmDataUnsubscribeCmd.java | 4 + .../cmd/v2/EntityDataUnsubscribeCmd.java | 4 + .../thingsboard/server/utils/MiscUtils.java | 1 + .../server/controller/AbstractWebTest.java | 4 + .../BaseEntityViewControllerTest.java | 20 +- ...AbstractMqttAttributesIntegrationTest.java | 14 +- ...AbstractMqttTimeseriesIntegrationTest.java | 30 +- .../routing/HashPartitionServiceTest.java | 3 +- .../queue/TbMsgPackProcessingContextTest.java | 2 +- .../util/EventDeduplicationExecutorTest.java | 2 +- common/actor/pom.xml | 2 +- .../server/actors/ActorSystemTest.java | 2 +- common/dao-api/pom.xml | 6 +- .../cassandra/AbstractCassandraCluster.java | 3 +- .../cassandra/guava/GuavaSessionBuilder.java | 31 +- .../server/dao/device/claim/ClaimResult.java | 2 + common/data/pom.xml | 2 +- .../server/common/data/ClaimRequest.java | 4 + .../server/common/data/HomeDashboardInfo.java | 2 + .../server/common/data/ShortCustomerInfo.java | 2 + ...esDeviceProfileProvisionConfiguration.java | 4 + ...esDeviceProfileProvisionConfiguration.java | 4 + ...edDeviceProfileProvisionConfiguration.java | 4 + .../common/data/query/DynamicValue.java | 9 + .../server/common/data/query/EntityData.java | 4 + .../server/common/data/query/EntityKey.java | 4 + .../server/common/data/query/TsValue.java | 4 + .../data/relation/EntityTypeFilter.java | 2 + .../relation/RelationsSearchParameters.java | 2 + .../server/common/data/UUIDConverterTest.java | 2 +- common/message/pom.xml | 2 +- common/queue/pom.xml | 2 +- .../TbServiceBusConsumerTemplate.java | 1 + .../server/queue/memory/InMemoryStorage.java | 5 +- .../queue/memory/InMemoryTbQueueConsumer.java | 1 + .../usagestats/DefaultTbApiUsageClient.java | 1 + common/stats/pom.xml | 4 +- common/transport/coap/pom.xml | 2 +- common/transport/http/pom.xml | 2 +- common/transport/mqtt/pom.xml | 2 +- .../mqtt/MqttSslHandlerProvider.java | 5 +- .../transport/mqtt/MqttTransportHandler.java | 21 +- .../server/transport/mqtt/util/SslUtil.java | 13 +- .../mqtt/util/MqttTopicFilterFactoryTest.java | 2 +- common/transport/transport-api/pom.xml | 2 +- .../transport/util/ProtoWithFSTService.java | 1 + common/util/pom.xml | 6 +- dao/pom.xml | 2 +- .../org/thingsboard/server/dao/DaoUtil.java | 4 +- .../server/dao/alarm/BaseAlarmService.java | 2 +- .../server/dao/audit/AuditLogServiceImpl.java | 4 + .../dao/audit/DummyAuditLogServiceImpl.java | 8 +- .../dao/entityview/EntityViewServiceImpl.java | 1 + .../HybridClientRegistrationRepository.java | 2 +- .../dao/relation/BaseRelationService.java | 2 + .../sql/dashboard/JpaDashboardInfoDao.java | 4 +- .../dao/sql/device/JpaDeviceProfileDao.java | 2 +- .../dao/sql/relation/RelationRepository.java | 2 +- .../server/dao/sql/rule/JpaRuleChainDao.java | 4 +- .../server/dao/sql/rule/JpaRuleNodeDao.java | 6 +- .../dao/sql/rule/JpaRuleNodeStateDao.java | 4 +- .../dao/sql/rule/RuleNodeRepository.java | 4 +- .../CassandraBaseTimeseriesDao.java | 3 +- .../server/dao/user/UserServiceImpl.java | 41 +- .../server/dao/util/mapping/JacksonUtil.java | 14 +- .../cassandra/io/sstable/Descriptor.java | 2 + .../io/sstable/format/SSTableFormat.java | 1 + .../apache/cassandra/io/util/FileUtils.java | 760 ++++++++++++++++++ .../nosql/CassandraPartitionsCacheTest.java | 8 +- .../dao/service/BaseAlarmServiceTest.java | 2 +- .../dao/service/BaseEntityServiceTest.java | 4 +- .../server/msa/AbstractContainerTest.java | 27 +- .../server/msa/ContainerTestSuite.java | 4 +- .../msa/connectivity/HttpClientTest.java | 7 +- .../msa/connectivity/MqttClientTest.java | 14 +- netty-mqtt/pom.xml | 9 +- pom.xml | 54 +- .../rule/engine/api/TbContext.java | 3 - rule-engine/rule-engine-components/pom.xml | 2 +- .../action/TbAbstractCustomerActionNode.java | 2 +- .../action/TbAbstractRelationActionNode.java | 2 +- .../thingsboard/rule/engine/geo/GeoUtil.java | 2 +- .../rule/engine/mail/EmailPojo.java | 4 + .../metadata/TbAbstractGetAttributesNode.java | 3 +- .../engine/metadata/TbGetTelemetryNode.java | 3 +- .../rule/engine/rest/TbHttpClient.java | 3 +- .../rule/engine/action/TbAlarmNodeTest.java | 10 +- .../engine/filter/TbJsFilterNodeTest.java | 20 +- .../engine/filter/TbJsSwitchNodeTest.java | 9 +- .../engine/mail/TbMsgToEmailNodeTest.java | 2 +- .../TbGetCustomerAttributeNodeTest.java | 9 +- .../profile/TbDeviceProfileNodeTest.java | 2 +- .../transform/TbChangeOriginatorNodeTest.java | 8 +- .../transform/TbTransformMsgNodeTest.java | 22 +- transport/coap/pom.xml | 2 +- transport/http/pom.xml | 2 +- transport/mqtt/pom.xml | 2 +- 120 files changed, 1148 insertions(+), 290 deletions(-) create mode 100644 dao/src/test/java/org/apache/cassandra/io/util/FileUtils.java diff --git a/application/pom.xml b/application/pom.xml index 62fd69d4f4..bbdf3a0bcd 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -275,7 +275,7 @@ org.mockito - mockito-all + mockito-core test diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java index c608c4a8a8..51100a8377 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java @@ -475,11 +475,6 @@ class DefaultTbContext implements TbContext { return mainCtx.getCassandraBufferedRateExecutor().submit(task); } - @Override - public RedisTemplate getRedisTemplate() { - return mainCtx.getRedisTemplate(); - } - @Override public PageData findRuleNodeStates(PageLink pageLink) { if (log.isDebugEnabled()) { diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeActorMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeActorMessageProcessor.java index 9e307df8c0..d0dbc66963 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeActorMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeActorMessageProcessor.java @@ -147,7 +147,7 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor componentClazz = Class.forName(ruleNode.getType()); - tbNode = (TbNode) (componentClazz.newInstance()); + tbNode = (TbNode) (componentClazz.getDeclaredConstructor().newInstance()); tbNode.init(defaultCtx, new TbNodeConfiguration(ruleNode.getConfiguration())); } return tbNode; diff --git a/application/src/main/java/org/thingsboard/server/config/CustomOAuth2AuthorizationRequestResolver.java b/application/src/main/java/org/thingsboard/server/config/CustomOAuth2AuthorizationRequestResolver.java index 0fcaf90525..bbcb7d656a 100644 --- a/application/src/main/java/org/thingsboard/server/config/CustomOAuth2AuthorizationRequestResolver.java +++ b/application/src/main/java/org/thingsboard/server/config/CustomOAuth2AuthorizationRequestResolver.java @@ -91,6 +91,7 @@ public class CustomOAuth2AuthorizationRequestResolver implements OAuth2Authoriza return action; } + @SuppressWarnings("deprecation") private OAuth2AuthorizationRequest resolve(HttpServletRequest request, String registrationId, String redirectUriAction) { if (registrationId == null) { return null; diff --git a/application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java b/application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java index a012bd7766..b70c4e2a7c 100644 --- a/application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java +++ b/application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java @@ -127,7 +127,7 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt } protected JwtTokenAuthenticationProcessingFilter buildJwtTokenAuthenticationProcessingFilter() throws Exception { - List pathsToSkip = new ArrayList(Arrays.asList(NON_TOKEN_BASED_AUTH_ENTRY_POINTS)); + List pathsToSkip = new ArrayList<>(Arrays.asList(NON_TOKEN_BASED_AUTH_ENTRY_POINTS)); pathsToSkip.addAll(Arrays.asList(WS_TOKEN_BASED_AUTH_ENTRY_POINT, TOKEN_REFRESH_ENTRY_POINT, FORM_BASED_LOGIN_ENTRY_POINT, PUBLIC_LOGIN_ENTRY_POINT, DEVICE_API_ENTRY_POINT, WEBJARS_ENTRY_POINT)); SkipPathRequestMatcher matcher = new SkipPathRequestMatcher(pathsToSkip, TOKEN_BASED_AUTH_ENTRY_POINT); diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index c5b3b28167..3a315be459 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -645,6 +645,7 @@ public abstract class BaseController { return ruleNode; } + @SuppressWarnings("unchecked") protected I emptyId(EntityType entityType) { return (I) EntityIdFactory.getByTypeAndUuid(entityType, ModelConstants.NULL_UUID); } @@ -759,6 +760,7 @@ public abstract class BaseController { entityNode = json.createObjectNode(); if (actionType == ActionType.ATTRIBUTES_UPDATED) { String scope = extractParameter(String.class, 0, additionalInfo); + @SuppressWarnings("unchecked") List attributes = extractParameter(List.class, 1, additionalInfo); metaData.putValue("scope", scope); if (attributes != null) { @@ -768,6 +770,7 @@ public abstract class BaseController { } } else if (actionType == ActionType.ATTRIBUTES_DELETED) { String scope = extractParameter(String.class, 0, additionalInfo); + @SuppressWarnings("unchecked") List keys = extractParameter(List.class, 1, additionalInfo); metaData.putValue("scope", scope); ArrayNode attrsArrayNode = entityNode.putArray("attributes"); @@ -775,9 +778,11 @@ public abstract class BaseController { keys.forEach(attrsArrayNode::add); } } else if (actionType == ActionType.TIMESERIES_UPDATED) { + @SuppressWarnings("unchecked") List timeseries = extractParameter(List.class, 0, additionalInfo); addTimeseries(entityNode, timeseries); } else if (actionType == ActionType.TIMESERIES_DELETED) { + @SuppressWarnings("unchecked") List keys = extractParameter(List.class, 0, additionalInfo); if (keys != null) { ArrayNode timeseriesArrayNode = entityNode.putArray("timeseries"); diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java index 2d2342556c..6250975b01 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java @@ -63,7 +63,7 @@ import java.util.List; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; -import static org.apache.commons.lang.StringUtils.isBlank; +import static org.apache.commons.lang3.StringUtils.isBlank; import static org.thingsboard.server.controller.CustomerController.CUSTOMER_ID; /** diff --git a/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java b/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java index bd490efdba..c0a9f5e7c5 100644 --- a/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java +++ b/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java @@ -24,6 +24,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; import org.springframework.core.env.Environment; +import org.springframework.core.env.Profiles; import org.springframework.core.type.filter.AnnotationTypeFilter; import org.springframework.stereotype.Service; import org.thingsboard.rule.engine.api.NodeConfiguration; @@ -69,7 +70,7 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe private ObjectMapper mapper = new ObjectMapper(); private boolean isInstall() { - return environment.acceptsProfiles("install"); + return environment.acceptsProfiles(Profiles.of("install")); } @PostConstruct @@ -185,7 +186,7 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe nodeDefinition.setRelationTypes(getRelationTypesWithFailureRelation(nodeAnnotation)); nodeDefinition.setCustomRelations(nodeAnnotation.customRelations()); Class configClazz = nodeAnnotation.configClazz(); - NodeConfiguration config = configClazz.newInstance(); + NodeConfiguration config = configClazz.getDeclaredConstructor().newInstance(); NodeConfiguration defaultConfiguration = config.defaultConfiguration(); nodeDefinition.setDefaultConfiguration(mapper.valueToTree(defaultConfiguration)); nodeDefinition.setUiResources(nodeAnnotation.uiResources()); diff --git a/application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java b/application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java index 2793503a81..3bd540048f 100644 --- a/application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java +++ b/application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java @@ -20,7 +20,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang.RandomStringUtils; +import org.apache.commons.lang3.RandomStringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; diff --git a/application/src/main/java/org/thingsboard/server/service/install/cql/CassandraDbHelper.java b/application/src/main/java/org/thingsboard/server/service/install/cql/CassandraDbHelper.java index 606bb34432..cb987a5e65 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/cql/CassandraDbHelper.java +++ b/application/src/main/java/org/thingsboard/server/service/install/cql/CassandraDbHelper.java @@ -146,17 +146,17 @@ public class CassandraDbHelper { if (row.isNull(index)) { return null; } else if (type.getProtocolCode() == ProtocolConstants.DataType.DOUBLE) { - str = new Double(row.getDouble(index)).toString(); + str = Double.valueOf(row.getDouble(index)).toString(); } else if (type.getProtocolCode() == ProtocolConstants.DataType.INT) { - str = new Integer(row.getInt(index)).toString(); + str = Integer.valueOf(row.getInt(index)).toString(); } else if (type.getProtocolCode() == ProtocolConstants.DataType.BIGINT) { - str = new Long(row.getLong(index)).toString(); + str = Long.valueOf(row.getLong(index)).toString(); } else if (type.getProtocolCode() == ProtocolConstants.DataType.UUID) { str = row.getUuid(index).toString(); } else if (type.getProtocolCode() == ProtocolConstants.DataType.TIMEUUID) { str = row.getUuid(index).toString(); } else if (type.getProtocolCode() == ProtocolConstants.DataType.FLOAT) { - str = new Float(row.getFloat(index)).toString(); + str = Float.valueOf(row.getFloat(index)).toString(); } else if (type.getProtocolCode() == ProtocolConstants.DataType.TIMESTAMP) { str = ""+row.getInstant(index).toEpochMilli(); } else { diff --git a/application/src/main/java/org/thingsboard/server/service/install/migrate/CassandraToSqlColumn.java b/application/src/main/java/org/thingsboard/server/service/install/migrate/CassandraToSqlColumn.java index bc53134973..f841621bbc 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/migrate/CassandraToSqlColumn.java +++ b/application/src/main/java/org/thingsboard/server/service/install/migrate/CassandraToSqlColumn.java @@ -153,7 +153,8 @@ public class CassandraToSqlColumn { sqlInsertStatement.setBoolean(this.sqlIndex, Boolean.parseBoolean(value)); break; case ENUM_TO_INT: - Enum enumVal = Enum.valueOf(this.enumClass, value); + @SuppressWarnings("unchecked") + Enum enumVal = Enum.valueOf(this.enumClass, value); int intValue = enumVal.ordinal(); sqlInsertStatement.setInt(this.sqlIndex, intValue); break; diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java index 3eebf8ff93..4bbe7c46f2 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java @@ -57,7 +57,7 @@ import java.util.List; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; -import static org.apache.commons.lang.StringUtils.isBlank; +import static org.apache.commons.lang3.StringUtils.isBlank; import static org.thingsboard.server.service.install.DatabaseHelper.objectMapper; @Service diff --git a/application/src/main/java/org/thingsboard/server/service/query/DefaultEntityQueryService.java b/application/src/main/java/org/thingsboard/server/service/query/DefaultEntityQueryService.java index 39a1c46325..7e1101dfc8 100644 --- a/application/src/main/java/org/thingsboard/server/service/query/DefaultEntityQueryService.java +++ b/application/src/main/java/org/thingsboard/server/service/query/DefaultEntityQueryService.java @@ -206,7 +206,7 @@ public class DefaultEntityQueryService implements EntityQueryService { addItemsToArrayNode(json.putArray("entityTypes"), types); addItemsToArrayNode(json.putArray("timeseries"), timeseriesKeys); addItemsToArrayNode(json.putArray("attribute"), attributesKeys); - response.setResult(new ResponseEntity(json, HttpStatus.OK)); + response.setResult(new ResponseEntity<>(json, HttpStatus.OK)); } private void replyWithEmptyResponse(DeferredResult response) { diff --git a/application/src/main/java/org/thingsboard/server/service/script/AbstractNashornJsInvokeService.java b/application/src/main/java/org/thingsboard/server/service/script/AbstractNashornJsInvokeService.java index 4aae3263d5..1d7a5d9533 100644 --- a/application/src/main/java/org/thingsboard/server/service/script/AbstractNashornJsInvokeService.java +++ b/application/src/main/java/org/thingsboard/server/service/script/AbstractNashornJsInvokeService.java @@ -21,7 +21,6 @@ import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import delight.nashornsandbox.NashornSandbox; import delight.nashornsandbox.NashornSandboxes; -import jdk.nashorn.api.scripting.NashornScriptEngineFactory; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; @@ -33,6 +32,7 @@ import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.script.Invocable; import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; import javax.script.ScriptException; import java.util.UUID; import java.util.concurrent.ExecutionException; @@ -97,8 +97,8 @@ public abstract class AbstractNashornJsInvokeService extends AbstractJsInvokeSer sandbox.allowLoadFunctions(true); sandbox.setMaxPreparedStatements(30); } else { - NashornScriptEngineFactory factory = new NashornScriptEngineFactory(); - engine = factory.getScriptEngine(new String[]{"--no-java"}); + ScriptEngineManager factory = new ScriptEngineManager(); + engine = factory.getEngineByName("nashorn"); } } diff --git a/application/src/main/java/org/thingsboard/server/service/security/auth/jwt/SkipPathRequestMatcher.java b/application/src/main/java/org/thingsboard/server/service/security/auth/jwt/SkipPathRequestMatcher.java index d9f4b976eb..331bbc6ef6 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/auth/jwt/SkipPathRequestMatcher.java +++ b/application/src/main/java/org/thingsboard/server/service/security/auth/jwt/SkipPathRequestMatcher.java @@ -29,7 +29,7 @@ public class SkipPathRequestMatcher implements RequestMatcher { private RequestMatcher processingMatcher; public SkipPathRequestMatcher(List pathsToSkip, String processingPath) { - Assert.notNull(pathsToSkip); + Assert.notNull(pathsToSkip, "List of paths to skip is required."); List m = pathsToSkip.stream().map(path -> new AntPathRequestMatcher(path)).collect(Collectors.toList()); matchers = new OrRequestMatcher(m); processingMatcher = new AntPathRequestMatcher(processingPath); diff --git a/application/src/main/java/org/thingsboard/server/service/security/model/token/JwtTokenFactory.java b/application/src/main/java/org/thingsboard/server/service/security/model/token/JwtTokenFactory.java index b4e26c1447..cfbf051cad 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/model/token/JwtTokenFactory.java +++ b/application/src/main/java/org/thingsboard/server/service/security/model/token/JwtTokenFactory.java @@ -100,6 +100,7 @@ public class JwtTokenFactory { Jws jwsClaims = rawAccessToken.parseClaims(settings.getTokenSigningKey()); Claims claims = jwsClaims.getBody(); String subject = claims.getSubject(); + @SuppressWarnings("unchecked") List scopes = claims.get(SCOPES, List.class); if (scopes == null || scopes.isEmpty()) { throw new IllegalArgumentException("JWT Token doesn't have any scopes"); @@ -155,6 +156,7 @@ public class JwtTokenFactory { Jws jwsClaims = rawAccessToken.parseClaims(settings.getTokenSigningKey()); Claims claims = jwsClaims.getBody(); String subject = claims.getSubject(); + @SuppressWarnings("unchecked") List scopes = claims.get(SCOPES, List.class); if (scopes == null || scopes.isEmpty()) { throw new IllegalArgumentException("Refresh Token doesn't have any scopes"); diff --git a/application/src/main/java/org/thingsboard/server/service/security/permission/CustomerUserPermissions.java b/application/src/main/java/org/thingsboard/server/service/security/permission/CustomerUserPermissions.java index a92b50cda8..4b2c22f501 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/permission/CustomerUserPermissions.java +++ b/application/src/main/java/org/thingsboard/server/service/security/permission/CustomerUserPermissions.java @@ -47,6 +47,7 @@ public class CustomerUserPermissions extends AbstractPermissions { Operation.READ_ATTRIBUTES, Operation.READ_TELEMETRY, Operation.RPC_CALL, Operation.CLAIM_DEVICES) { @Override + @SuppressWarnings("unchecked") public boolean hasPermission(SecurityUser user, Operation operation, EntityId entityId, HasTenantId entity) { if (!super.hasPermission(user, operation, entityId, entity)) { @@ -69,6 +70,7 @@ public class CustomerUserPermissions extends AbstractPermissions { new PermissionChecker.GenericPermissionChecker(Operation.READ, Operation.READ_ATTRIBUTES, Operation.READ_TELEMETRY) { @Override + @SuppressWarnings("unchecked") public boolean hasPermission(SecurityUser user, Operation operation, EntityId entityId, HasTenantId entity) { if (!super.hasPermission(user, operation, entityId, entity)) { return false; @@ -119,6 +121,7 @@ public class CustomerUserPermissions extends AbstractPermissions { private static final PermissionChecker widgetsPermissionChecker = new PermissionChecker.GenericPermissionChecker(Operation.READ) { @Override + @SuppressWarnings("unchecked") public boolean hasPermission(SecurityUser user, Operation operation, EntityId entityId, HasTenantId entity) { if (!super.hasPermission(user, operation, entityId, entity)) { return false; diff --git a/application/src/main/java/org/thingsboard/server/service/security/permission/DefaultAccessControlService.java b/application/src/main/java/org/thingsboard/server/service/security/permission/DefaultAccessControlService.java index 624e1743ca..0e56963464 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/permission/DefaultAccessControlService.java +++ b/application/src/main/java/org/thingsboard/server/service/security/permission/DefaultAccessControlService.java @@ -56,6 +56,7 @@ public class DefaultAccessControlService implements AccessControlService { } @Override + @SuppressWarnings("unchecked") public void checkPermission(SecurityUser user, Resource resource, Operation operation, I entityId, T entity) throws ThingsboardException { PermissionChecker permissionChecker = getPermissionChecker(user.getAuthority(), resource); diff --git a/application/src/main/java/org/thingsboard/server/service/security/permission/TenantAdminPermissions.java b/application/src/main/java/org/thingsboard/server/service/security/permission/TenantAdminPermissions.java index b8d2c539cd..f56e1e0554 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/permission/TenantAdminPermissions.java +++ b/application/src/main/java/org/thingsboard/server/service/security/permission/TenantAdminPermissions.java @@ -59,6 +59,7 @@ public class TenantAdminPermissions extends AbstractPermissions { new PermissionChecker.GenericPermissionChecker(Operation.READ, Operation.READ_ATTRIBUTES, Operation.READ_TELEMETRY) { @Override + @SuppressWarnings("unchecked") public boolean hasPermission(SecurityUser user, Operation operation, EntityId entityId, HasTenantId entity) { if (!super.hasPermission(user, operation, entityId, entity)) { return false; diff --git a/application/src/main/java/org/thingsboard/server/service/security/system/DefaultSystemSecurityService.java b/application/src/main/java/org/thingsboard/server/service/security/system/DefaultSystemSecurityService.java index 9ebff31ad4..c86b1cdcfe 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/system/DefaultSystemSecurityService.java +++ b/application/src/main/java/org/thingsboard/server/service/security/system/DefaultSystemSecurityService.java @@ -15,8 +15,8 @@ */ package org.thingsboard.server.service.security.system; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -49,6 +49,7 @@ import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.settings.AdminSettingsService; import org.thingsboard.server.dao.user.UserService; import org.thingsboard.server.dao.user.UserServiceImpl; +import org.thingsboard.server.dao.util.mapping.JacksonUtil; import org.thingsboard.server.service.security.exception.UserPasswordExpiredException; import org.thingsboard.server.utils.MiscUtils; @@ -65,8 +66,6 @@ import static org.thingsboard.server.common.data.CacheConstants.SECURITY_SETTING @Slf4j public class DefaultSystemSecurityService implements SystemSecurityService { - private static final ObjectMapper objectMapper = new ObjectMapper(); - @Autowired private AdminSettingsService adminSettingsService; @@ -89,7 +88,7 @@ public class DefaultSystemSecurityService implements SystemSecurityService { AdminSettings adminSettings = adminSettingsService.findAdminSettingsByKey(tenantId, "securitySettings"); if (adminSettings != null) { try { - securitySettings = objectMapper.treeToValue(adminSettings.getJsonValue(), SecuritySettings.class); + securitySettings = JacksonUtil.convertValue(adminSettings.getJsonValue(), SecuritySettings.class); } catch (Exception e) { throw new RuntimeException("Failed to load security settings!", e); } @@ -109,10 +108,10 @@ public class DefaultSystemSecurityService implements SystemSecurityService { adminSettings = new AdminSettings(); adminSettings.setKey("securitySettings"); } - adminSettings.setJsonValue(objectMapper.valueToTree(securitySettings)); + adminSettings.setJsonValue(JacksonUtil.valueToTree(securitySettings)); AdminSettings savedAdminSettings = adminSettingsService.saveAdminSettings(tenantId, adminSettings); try { - return objectMapper.treeToValue(savedAdminSettings.getJsonValue(), SecuritySettings.class); + return JacksonUtil.convertValue(savedAdminSettings.getJsonValue(), SecuritySettings.class); } catch (Exception e) { throw new RuntimeException("Failed to load security settings!", e); } @@ -189,7 +188,7 @@ public class DefaultSystemSecurityService implements SystemSecurityService { JsonNode additionalInfo = user.getAdditionalInfo(); if (additionalInfo instanceof ObjectNode && additionalInfo.has(UserServiceImpl.USER_PASSWORD_HISTORY)) { JsonNode userPasswordHistoryJson = additionalInfo.get(UserServiceImpl.USER_PASSWORD_HISTORY); - Map userPasswordHistoryMap = objectMapper.convertValue(userPasswordHistoryJson, Map.class); + Map userPasswordHistoryMap = JacksonUtil.convertValue(userPasswordHistoryJson, new TypeReference<>() {}); for (Map.Entry entry : userPasswordHistoryMap.entrySet()) { if (encoder.matches(password, entry.getValue()) && Long.parseLong(entry.getKey()) > passwordReuseFrequencyTs) { throw new DataValidationException("Password was already used for the last " + passwordPolicy.getPasswordReuseFrequencyDays() + " days"); diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbEntityDataSubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbEntityDataSubscriptionService.java index 1b455085eb..fe2fbce573 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbEntityDataSubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbEntityDataSubscriptionService.java @@ -318,6 +318,7 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc return ctx; } + @SuppressWarnings("unchecked") private T getSubCtx(String sessionId, int cmdId) { Map sessionSubs = subscriptionsBySessionId.get(sessionId); if (sessionSubs != null) { diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbLocalSubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbLocalSubscriptionService.java index 868d14ac3e..ee00b28562 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbLocalSubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbLocalSubscriptionService.java @@ -123,6 +123,7 @@ public class DefaultTbLocalSubscriptionService implements TbLocalSubscriptionSer } @Override + @SuppressWarnings("unchecked") public void onSubscriptionUpdate(String sessionId, TelemetrySubscriptionUpdate update, TbCallback callback) { TbSubscription subscription = subscriptionsBySessionId .getOrDefault(sessionId, Collections.emptyMap()).get(update.getSubscriptionId()); @@ -143,6 +144,7 @@ public class DefaultTbLocalSubscriptionService implements TbLocalSubscriptionSer } @Override + @SuppressWarnings("unchecked") public void onSubscriptionUpdate(String sessionId, AlarmSubscriptionUpdate update, TbCallback callback) { TbSubscription subscription = subscriptionsBySessionId .getOrDefault(sessionId, Collections.emptyMap()).get(update.getSubscriptionId()); diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/TbAbstractDataSubCtx.java b/application/src/main/java/org/thingsboard/server/service/subscription/TbAbstractDataSubCtx.java index 9b03e40f1e..a200f31a3f 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/TbAbstractDataSubCtx.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/TbAbstractDataSubCtx.java @@ -264,6 +264,7 @@ public abstract class TbAbstractDataSubCtx T doGetAsyncTyped(String urlTemplate, TypeReference responseType, Object... urlVariables) throws Exception { + return readResponse(doGetAsync(urlTemplate, urlVariables).andExpect(status().isOk()), responseType); + } + protected ResultActions doGetAsync(String urlTemplate, Object... urlVariables) throws Exception { MockHttpServletRequestBuilder getRequest; getRequest = get(urlTemplate, urlVariables); diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java index 35ff3703c0..c6d0073d83 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java @@ -347,8 +347,8 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes Thread.sleep(1000); - List> values = doGetAsync("/api/plugins/telemetry/ENTITY_VIEW/" + savedView.getId().getId().toString() + - "/values/attributes?keys=" + String.join(",", actualAttributesSet), List.class); + List> values = doGetAsyncTyped("/api/plugins/telemetry/ENTITY_VIEW/" + savedView.getId().getId().toString() + + "/values/attributes?keys=" + String.join(",", actualAttributesSet), new TypeReference<>() {}); assertEquals("value1", getValue(values, "caKey1")); assertEquals(true, getValue(values, "caKey2")); @@ -364,8 +364,8 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes Set expectedActualAttributesSet = new HashSet<>(Arrays.asList("caKey1", "caKey2", "caKey3", "caKey4")); assertTrue(actualAttributesSet.containsAll(expectedActualAttributesSet)); - List> valueTelemetryOfDevices = doGetAsync("/api/plugins/telemetry/DEVICE/" + testDevice.getId().getId().toString() + - "/values/attributes?keys=" + String.join(",", actualAttributesSet), List.class); + List> valueTelemetryOfDevices = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + testDevice.getId().getId().toString() + + "/values/attributes?keys=" + String.join(",", actualAttributesSet), new TypeReference<>() {}); EntityView view = new EntityView(); view.setEntityId(testDevice.getId()); @@ -379,8 +379,8 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes Thread.sleep(1000); - List> values = doGetAsync("/api/plugins/telemetry/ENTITY_VIEW/" + savedView.getId().getId().toString() + - "/values/attributes?keys=" + String.join(",", actualAttributesSet), List.class); + List> values = doGetAsyncTyped("/api/plugins/telemetry/ENTITY_VIEW/" + savedView.getId().getId().toString() + + "/values/attributes?keys=" + String.join(",", actualAttributesSet), new TypeReference<>() {}); assertEquals(0, values.size()); } @@ -449,12 +449,12 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes } private Set getTelemetryKeys(String type, String id) throws Exception { - return new HashSet<>(doGetAsync("/api/plugins/telemetry/" + type + "/" + id + "/keys/timeseries", List.class)); + return new HashSet<>(doGetAsyncTyped("/api/plugins/telemetry/" + type + "/" + id + "/keys/timeseries", new TypeReference<>() {})); } private Map>> getTelemetryValues(String type, String id, Set keys, Long startTs, Long endTs) throws Exception { - return doGetAsync("/api/plugins/telemetry/" + type + "/" + id + - "/values/timeseries?keys=" + String.join(",", keys) + "&startTs=" + startTs + "&endTs=" + endTs, Map.class); + return doGetAsyncTyped("/api/plugins/telemetry/" + type + "/" + id + + "/values/timeseries?keys=" + String.join(",", keys) + "&startTs=" + startTs + "&endTs=" + endTs, new TypeReference<>() {}); } private Set getAttributesByKeys(String stringKV) throws Exception { @@ -479,7 +479,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes client.publish("v1/devices/me/attributes", message); Thread.sleep(1000); client.disconnect(); - return new HashSet<>(doGetAsync("/api/plugins/telemetry/DEVICE/" + viewDeviceId + "/keys/attributes", List.class)); + return new HashSet<>(doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + viewDeviceId + "/keys/attributes", new TypeReference<>() {})); } private Object getValue(List> values, String stringValue) { diff --git a/application/src/test/java/org/thingsboard/server/mqtt/telemetry/attributes/AbstractMqttAttributesIntegrationTest.java b/application/src/test/java/org/thingsboard/server/mqtt/telemetry/attributes/AbstractMqttAttributesIntegrationTest.java index d048546323..874d55606d 100644 --- a/application/src/test/java/org/thingsboard/server/mqtt/telemetry/attributes/AbstractMqttAttributesIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/mqtt/telemetry/attributes/AbstractMqttAttributesIntegrationTest.java @@ -16,6 +16,7 @@ package org.thingsboard.server.mqtt.telemetry.attributes; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; import lombok.extern.slf4j.Slf4j; import org.eclipse.paho.client.mqttv3.MqttAsyncClient; import org.junit.After; @@ -80,7 +81,7 @@ public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqtt List actualKeys = null; while (start <= end) { - actualKeys = doGetAsync("/api/plugins/telemetry/DEVICE/" + deviceId + "/keys/attributes/CLIENT_SCOPE", List.class); + actualKeys = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + deviceId + "/keys/attributes/CLIENT_SCOPE", new TypeReference<>() {}); if (actualKeys.size() == expectedKeys.size()) { break; } @@ -96,7 +97,7 @@ public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqtt assertEquals(expectedKeySet, actualKeySet); String getAttributesValuesUrl = getAttributesValuesUrl(deviceId, actualKeySet); - List> values = doGetAsync(getAttributesValuesUrl, List.class); + List> values = doGetAsyncTyped(getAttributesValuesUrl, new TypeReference<>() {}); assertAttributesValues(values, expectedKeySet); String deleteAttributesUrl = "/api/plugins/telemetry/DEVICE/" + deviceId + "/CLIENT_SCOPE?keys=" + String.join(",", actualKeySet); doDelete(deleteAttributesUrl); @@ -121,10 +122,10 @@ public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqtt Thread.sleep(2000); - List firstDeviceActualKeys = doGetAsync("/api/plugins/telemetry/DEVICE/" + firstDevice.getId() + "/keys/attributes/CLIENT_SCOPE", List.class); + List firstDeviceActualKeys = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + firstDevice.getId() + "/keys/attributes/CLIENT_SCOPE", new TypeReference<>() {}); Set firstDeviceActualKeySet = new HashSet<>(firstDeviceActualKeys); - List secondDeviceActualKeys = doGetAsync("/api/plugins/telemetry/DEVICE/" + secondDevice.getId() + "/keys/attributes/CLIENT_SCOPE", List.class); + List secondDeviceActualKeys = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + secondDevice.getId() + "/keys/attributes/CLIENT_SCOPE", new TypeReference<>() {}); Set secondDeviceActualKeySet = new HashSet<>(secondDeviceActualKeys); Set expectedKeySet = new HashSet<>(expectedKeys); @@ -135,14 +136,15 @@ public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqtt String getAttributesValuesUrlFirstDevice = getAttributesValuesUrl(firstDevice.getId(), firstDeviceActualKeySet); String getAttributesValuesUrlSecondDevice = getAttributesValuesUrl(firstDevice.getId(), secondDeviceActualKeySet); - List> firstDeviceValues = doGetAsync(getAttributesValuesUrlFirstDevice, List.class); - List> secondDeviceValues = doGetAsync(getAttributesValuesUrlSecondDevice, List.class); + List> firstDeviceValues = doGetAsyncTyped(getAttributesValuesUrlFirstDevice, new TypeReference<>() {}); + List> secondDeviceValues = doGetAsyncTyped(getAttributesValuesUrlSecondDevice, new TypeReference<>() {}); assertAttributesValues(firstDeviceValues, expectedKeySet); assertAttributesValues(secondDeviceValues, expectedKeySet); } + @SuppressWarnings("unchecked") protected void assertAttributesValues(List> deviceValues, Set expectedKeySet) throws JsonProcessingException { for (Map map : deviceValues) { String key = (String) map.get("key"); diff --git a/application/src/test/java/org/thingsboard/server/mqtt/telemetry/timeseries/AbstractMqttTimeseriesIntegrationTest.java b/application/src/test/java/org/thingsboard/server/mqtt/telemetry/timeseries/AbstractMqttTimeseriesIntegrationTest.java index 9984c9faae..9ecc3415c2 100644 --- a/application/src/test/java/org/thingsboard/server/mqtt/telemetry/timeseries/AbstractMqttTimeseriesIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/mqtt/telemetry/timeseries/AbstractMqttTimeseriesIntegrationTest.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.mqtt.telemetry.timeseries; +import com.fasterxml.jackson.core.type.TypeReference; import io.netty.handler.codec.mqtt.MqttQoS; import lombok.extern.slf4j.Slf4j; import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; @@ -25,6 +26,7 @@ import org.eclipse.paho.client.mqttv3.MqttMessage; import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.device.profile.MqttTopics; @@ -107,7 +109,7 @@ public abstract class AbstractMqttTimeseriesIntegrationTest extends AbstractMqtt List actualKeys = null; while (start <= end) { - actualKeys = doGetAsync("/api/plugins/telemetry/DEVICE/" + deviceId + "/keys/timeseries", List.class); + actualKeys = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + deviceId + "/keys/timeseries", new TypeReference<>() {}); if (actualKeys.size() == expectedKeys.size()) { break; } @@ -129,13 +131,13 @@ public abstract class AbstractMqttTimeseriesIntegrationTest extends AbstractMqtt } start = System.currentTimeMillis(); end = System.currentTimeMillis() + 5000; - Map>> values = null; + Map>> values = null; while (start <= end) { - values = doGetAsync(getTelemetryValuesUrl, Map.class); + values = doGetAsyncTyped(getTelemetryValuesUrl, new TypeReference<>() {}); boolean valid = values.size() == expectedKeys.size(); if (valid) { for (String key : expectedKeys) { - List> tsValues = values.get(key); + List> tsValues = values.get(key); if (tsValues != null && tsValues.size() > 0) { Object ts = tsValues.get(0).get("ts"); if (ts == null) { @@ -181,10 +183,10 @@ public abstract class AbstractMqttTimeseriesIntegrationTest extends AbstractMqtt Thread.sleep(2000); - List firstDeviceActualKeys = doGetAsync("/api/plugins/telemetry/DEVICE/" + firstDevice.getId() + "/keys/timeseries", List.class); + List firstDeviceActualKeys = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + firstDevice.getId() + "/keys/timeseries", new TypeReference<>() {}); Set firstDeviceActualKeySet = new HashSet<>(firstDeviceActualKeys); - List secondDeviceActualKeys = doGetAsync("/api/plugins/telemetry/DEVICE/" + secondDevice.getId() + "/keys/timeseries", List.class); + List secondDeviceActualKeys = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + secondDevice.getId() + "/keys/timeseries", new TypeReference<>() {}); Set secondDeviceActualKeySet = new HashSet<>(secondDeviceActualKeys); Set expectedKeySet = new HashSet<>(expectedKeys); @@ -195,8 +197,8 @@ public abstract class AbstractMqttTimeseriesIntegrationTest extends AbstractMqtt String getTelemetryValuesUrlFirstDevice = getTelemetryValuesUrl(firstDevice.getId(), firstDeviceActualKeySet); String getTelemetryValuesUrlSecondDevice = getTelemetryValuesUrl(firstDevice.getId(), secondDeviceActualKeySet); - Map>> firstDeviceValues = doGetAsync(getTelemetryValuesUrlFirstDevice, Map.class); - Map>> secondDeviceValues = doGetAsync(getTelemetryValuesUrlSecondDevice, Map.class); + Map>> firstDeviceValues = doGetAsyncTyped(getTelemetryValuesUrlFirstDevice, new TypeReference<>() {}); + Map>> secondDeviceValues = doGetAsyncTyped(getTelemetryValuesUrlSecondDevice, new TypeReference<>() {}); assertGatewayDeviceData(firstDeviceValues, expectedKeys); assertGatewayDeviceData(secondDeviceValues, expectedKeys); @@ -212,7 +214,7 @@ public abstract class AbstractMqttTimeseriesIntegrationTest extends AbstractMqtt return "/api/plugins/telemetry/DEVICE/" + deviceId + "/values/timeseries?startTs=0&endTs=25000&keys=" + String.join(",", actualKeySet); } - private void assertGatewayDeviceData(Map>> deviceValues, List expectedKeys) { + private void assertGatewayDeviceData(Map>> deviceValues, List expectedKeys) { assertEquals(2, deviceValues.get(expectedKeys.get(0)).size()); assertEquals(2, deviceValues.get(expectedKeys.get(1)).size()); @@ -228,11 +230,11 @@ public abstract class AbstractMqttTimeseriesIntegrationTest extends AbstractMqtt } - private void assertValues(Map>> deviceValues, int arrayIndex) { - for (Map.Entry>> entry : deviceValues.entrySet()) { + private void assertValues(Map>> deviceValues, int arrayIndex) { + for (Map.Entry>> entry : deviceValues.entrySet()) { String key = entry.getKey(); - List> tsKv = entry.getValue(); - String value = tsKv.get(arrayIndex).get("value"); + List> tsKv = entry.getValue(); + String value = (String) tsKv.get(arrayIndex).get("value"); switch (key) { case "key1": assertEquals("value1", value); @@ -253,7 +255,7 @@ public abstract class AbstractMqttTimeseriesIntegrationTest extends AbstractMqtt } } - private void assertTs(Map>> deviceValues, List expectedKeys, int ts, int arrayIndex) { + private void assertTs(Map>> deviceValues, List expectedKeys, int ts, int arrayIndex) { assertEquals(ts, deviceValues.get(expectedKeys.get(0)).get(arrayIndex).get("ts")); assertEquals(ts, deviceValues.get(expectedKeys.get(1)).get(arrayIndex).get("ts")); assertEquals(ts, deviceValues.get(expectedKeys.get(2)).get(arrayIndex).get("ts")); diff --git a/application/src/test/java/org/thingsboard/server/service/cluster/routing/HashPartitionServiceTest.java b/application/src/test/java/org/thingsboard/server/service/cluster/routing/HashPartitionServiceTest.java index 7ce23368a9..88d7796af5 100644 --- a/application/src/test/java/org/thingsboard/server/service/cluster/routing/HashPartitionServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/cluster/routing/HashPartitionServiceTest.java @@ -21,12 +21,11 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import org.springframework.context.ApplicationEventPublisher; import org.springframework.test.util.ReflectionTestUtils; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.msg.queue.ServiceQueue; import org.thingsboard.server.queue.discovery.HashPartitionService; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; diff --git a/application/src/test/java/org/thingsboard/server/service/queue/TbMsgPackProcessingContextTest.java b/application/src/test/java/org/thingsboard/server/service/queue/TbMsgPackProcessingContextTest.java index 901fc27bb1..6c4e4a9426 100644 --- a/application/src/test/java/org/thingsboard/server/service/queue/TbMsgPackProcessingContextTest.java +++ b/application/src/test/java/org/thingsboard/server/service/queue/TbMsgPackProcessingContextTest.java @@ -20,7 +20,7 @@ import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.common.TbProtoQueueMsg; import org.thingsboard.server.service.queue.processing.TbRuleEngineSubmitStrategy; diff --git a/application/src/test/java/org/thingsboard/server/util/EventDeduplicationExecutorTest.java b/application/src/test/java/org/thingsboard/server/util/EventDeduplicationExecutorTest.java index c58f44e2eb..ac0b2342ec 100644 --- a/application/src/test/java/org/thingsboard/server/util/EventDeduplicationExecutorTest.java +++ b/application/src/test/java/org/thingsboard/server/util/EventDeduplicationExecutorTest.java @@ -20,7 +20,7 @@ import lombok.extern.slf4j.Slf4j; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import org.thingsboard.server.utils.EventDeduplicationExecutor; import java.util.concurrent.ExecutorService; diff --git a/common/actor/pom.xml b/common/actor/pom.xml index 6609648e7c..1f4849cb79 100644 --- a/common/actor/pom.xml +++ b/common/actor/pom.xml @@ -67,7 +67,7 @@ org.mockito - mockito-all + mockito-core test diff --git a/common/actor/src/test/java/org/thingsboard/server/actors/ActorSystemTest.java b/common/actor/src/test/java/org/thingsboard/server/actors/ActorSystemTest.java index 8ce0942f2a..31fae3d7a4 100644 --- a/common/actor/src/test/java/org/thingsboard/server/actors/ActorSystemTest.java +++ b/common/actor/src/test/java/org/thingsboard/server/actors/ActorSystemTest.java @@ -21,7 +21,7 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import org.thingsboard.server.common.data.id.DeviceId; import java.util.ArrayList; diff --git a/common/dao-api/pom.xml b/common/dao-api/pom.xml index b427846d91..ba30e5bb43 100644 --- a/common/dao-api/pom.xml +++ b/common/dao-api/pom.xml @@ -48,6 +48,10 @@ com.google.guava guava + + javax.annotation + javax.annotation-api + com.github.fge json-schema-validator @@ -99,7 +103,7 @@ org.mockito - mockito-all + mockito-core test diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/cassandra/AbstractCassandraCluster.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/cassandra/AbstractCassandraCluster.java index d03c0d167b..57b0e2a140 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/cassandra/AbstractCassandraCluster.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/cassandra/AbstractCassandraCluster.java @@ -23,6 +23,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.env.Environment; +import org.springframework.core.env.Profiles; import org.thingsboard.server.dao.cassandra.guava.GuavaSession; import org.thingsboard.server.dao.cassandra.guava.GuavaSessionBuilder; import org.thingsboard.server.dao.cassandra.guava.GuavaSessionUtils; @@ -77,7 +78,7 @@ public abstract class AbstractCassandraCluster { } private boolean isInstall() { - return environment.acceptsProfiles("install"); + return environment.acceptsProfiles(Profiles.of("install")); } private void initSession() { diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/cassandra/guava/GuavaSessionBuilder.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/cassandra/guava/GuavaSessionBuilder.java index 45f3e6fd6a..8187e5e6f2 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/cassandra/guava/GuavaSessionBuilder.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/cassandra/guava/GuavaSessionBuilder.java @@ -18,38 +18,25 @@ package org.thingsboard.server.dao.cassandra.guava; import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.config.DriverConfigLoader; import com.datastax.oss.driver.api.core.context.DriverContext; -import com.datastax.oss.driver.api.core.metadata.Node; -import com.datastax.oss.driver.api.core.metadata.NodeStateListener; -import com.datastax.oss.driver.api.core.metadata.schema.SchemaChangeListener; +import com.datastax.oss.driver.api.core.session.ProgrammaticArguments; import com.datastax.oss.driver.api.core.session.SessionBuilder; -import com.datastax.oss.driver.api.core.tracker.RequestTracker; -import com.datastax.oss.driver.api.core.type.codec.TypeCodec; import edu.umd.cs.findbugs.annotations.NonNull; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; public class GuavaSessionBuilder extends SessionBuilder { @Override protected DriverContext buildContext( DriverConfigLoader configLoader, - List> typeCodecs, - NodeStateListener nodeStateListener, - SchemaChangeListener schemaChangeListener, - RequestTracker requestTracker, - Map localDatacenters, - Map> nodeFilters, - ClassLoader classLoader) { + ProgrammaticArguments programmaticArguments) { return new GuavaDriverContext( configLoader, - typeCodecs, - nodeStateListener, - schemaChangeListener, - requestTracker, - localDatacenters, - nodeFilters, - classLoader); + programmaticArguments.getTypeCodecs(), + programmaticArguments.getNodeStateListener(), + programmaticArguments.getSchemaChangeListener(), + programmaticArguments.getRequestTracker(), + programmaticArguments.getLocalDatacenters(), + programmaticArguments.getNodeFilters(), + programmaticArguments.getClassLoader()); } @Override diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/claim/ClaimResult.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/claim/ClaimResult.java index 0dddc66ebe..fbf3256d8c 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/claim/ClaimResult.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/claim/ClaimResult.java @@ -18,9 +18,11 @@ package org.thingsboard.server.dao.device.claim; import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; import org.thingsboard.server.common.data.Device; @AllArgsConstructor +@NoArgsConstructor @Data public class ClaimResult { diff --git a/common/data/pom.xml b/common/data/pom.xml index 6d484bd107..79b3bc8e26 100644 --- a/common/data/pom.xml +++ b/common/data/pom.xml @@ -63,7 +63,7 @@ org.mockito - mockito-all + mockito-core test diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/ClaimRequest.java b/common/data/src/main/java/org/thingsboard/server/common/data/ClaimRequest.java index a9ef3473aa..a1dec1d216 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/ClaimRequest.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/ClaimRequest.java @@ -15,9 +15,13 @@ */ package org.thingsboard.server.common.data; +import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; @Data +@AllArgsConstructor +@NoArgsConstructor(force = true) public class ClaimRequest { private final String secretKey; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/HomeDashboardInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/HomeDashboardInfo.java index 1cbc1c737e..30d271af95 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/HomeDashboardInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/HomeDashboardInfo.java @@ -17,10 +17,12 @@ package org.thingsboard.server.common.data; import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; import org.thingsboard.server.common.data.id.DashboardId; @Data @AllArgsConstructor +@NoArgsConstructor public class HomeDashboardInfo { private DashboardId dashboardId; private boolean hideDashboardToolbar; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/ShortCustomerInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/ShortCustomerInfo.java index aa03cd7e59..11bd9e6955 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/ShortCustomerInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/ShortCustomerInfo.java @@ -17,6 +17,7 @@ package org.thingsboard.server.common.data; import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; import org.thingsboard.server.common.data.id.CustomerId; @@ -25,6 +26,7 @@ import org.thingsboard.server.common.data.id.CustomerId; */ @AllArgsConstructor +@NoArgsConstructor public class ShortCustomerInfo { @Getter @Setter diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AllowCreateNewDevicesDeviceProfileProvisionConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AllowCreateNewDevicesDeviceProfileProvisionConfiguration.java index 79532d34f3..2370dc9f11 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AllowCreateNewDevicesDeviceProfileProvisionConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AllowCreateNewDevicesDeviceProfileProvisionConfiguration.java @@ -15,10 +15,14 @@ */ package org.thingsboard.server.common.data.device.profile; +import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; import org.thingsboard.server.common.data.DeviceProfileProvisionType; @Data +@AllArgsConstructor +@NoArgsConstructor(force = true) public class AllowCreateNewDevicesDeviceProfileProvisionConfiguration implements DeviceProfileProvisionConfiguration { private final String provisionDeviceSecret; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/CheckPreProvisionedDevicesDeviceProfileProvisionConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/CheckPreProvisionedDevicesDeviceProfileProvisionConfiguration.java index 1c2c1e9eaa..e2e37d3979 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/CheckPreProvisionedDevicesDeviceProfileProvisionConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/CheckPreProvisionedDevicesDeviceProfileProvisionConfiguration.java @@ -15,10 +15,14 @@ */ package org.thingsboard.server.common.data.device.profile; +import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; import org.thingsboard.server.common.data.DeviceProfileProvisionType; @Data +@AllArgsConstructor +@NoArgsConstructor(force = true) public class CheckPreProvisionedDevicesDeviceProfileProvisionConfiguration implements DeviceProfileProvisionConfiguration { private final String provisionDeviceSecret; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DisabledDeviceProfileProvisionConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DisabledDeviceProfileProvisionConfiguration.java index 10021ddb1a..7c2d11c8eb 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DisabledDeviceProfileProvisionConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DisabledDeviceProfileProvisionConfiguration.java @@ -15,10 +15,14 @@ */ package org.thingsboard.server.common.data.device.profile; +import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; import org.thingsboard.server.common.data.DeviceProfileProvisionType; @Data +@AllArgsConstructor +@NoArgsConstructor(force = true) public class DisabledDeviceProfileProvisionConfiguration implements DeviceProfileProvisionConfiguration { private final String provisionDeviceSecret; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/DynamicValue.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/DynamicValue.java index 3d46f8d2ab..25be8d7502 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/DynamicValue.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/DynamicValue.java @@ -15,7 +15,9 @@ */ package org.thingsboard.server.common.data.query; +import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import lombok.Getter; @@ -30,4 +32,11 @@ public class DynamicValue { @Getter private final String sourceAttribute; + @JsonCreator + public DynamicValue(@JsonProperty("sourceType") DynamicValueSourceType sourceType, + @JsonProperty("sourceAttribute") String sourceAttribute) { + this.sourceType = sourceType; + this.sourceAttribute = sourceAttribute; + } + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityData.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityData.java index 0998d348d4..2ff6902f75 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityData.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityData.java @@ -15,12 +15,16 @@ */ package org.thingsboard.server.common.data.query; +import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; import org.thingsboard.server.common.data.id.EntityId; import java.util.Map; @Data +@AllArgsConstructor +@NoArgsConstructor(force = true) public class EntityData { private final EntityId entityId; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityKey.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityKey.java index 191ef02f11..54fc13f1f4 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityKey.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityKey.java @@ -15,9 +15,13 @@ */ package org.thingsboard.server.common.data.query; +import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; @Data +@AllArgsConstructor +@NoArgsConstructor(force = true) public class EntityKey { private final EntityKeyType type; private final String key; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/TsValue.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/TsValue.java index bb2735b2d0..25d2ac76aa 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/TsValue.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/TsValue.java @@ -15,9 +15,13 @@ */ package org.thingsboard.server.common.data.query; +import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; @Data +@AllArgsConstructor +@NoArgsConstructor(force = true) public class TsValue { private final long ts; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityTypeFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityTypeFilter.java index 8b9849d6a1..3660ea02c5 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityTypeFilter.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityTypeFilter.java @@ -17,6 +17,7 @@ package org.thingsboard.server.common.data.relation; import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; import org.thingsboard.server.common.data.EntityType; import java.util.List; @@ -26,6 +27,7 @@ import java.util.List; */ @Data @AllArgsConstructor +@NoArgsConstructor public class EntityTypeFilter { private String relationType; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/relation/RelationsSearchParameters.java b/common/data/src/main/java/org/thingsboard/server/common/data/relation/RelationsSearchParameters.java index f44337ff29..ed63a5ffe5 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/relation/RelationsSearchParameters.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/relation/RelationsSearchParameters.java @@ -17,6 +17,7 @@ package org.thingsboard.server.common.data.relation; import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityIdFactory; @@ -28,6 +29,7 @@ import java.util.UUID; */ @Data @AllArgsConstructor +@NoArgsConstructor public class RelationsSearchParameters { private UUID rootId; diff --git a/common/data/src/test/java/org/thingsboard/server/common/data/UUIDConverterTest.java b/common/data/src/test/java/org/thingsboard/server/common/data/UUIDConverterTest.java index adb173f367..0f5bf5f724 100644 --- a/common/data/src/test/java/org/thingsboard/server/common/data/UUIDConverterTest.java +++ b/common/data/src/test/java/org/thingsboard/server/common/data/UUIDConverterTest.java @@ -19,7 +19,7 @@ import com.datastax.oss.driver.api.core.uuid.Uuids; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import java.util.ArrayList; import java.util.Arrays; diff --git a/common/message/pom.xml b/common/message/pom.xml index 8bc2653bb0..06ba4aff3b 100644 --- a/common/message/pom.xml +++ b/common/message/pom.xml @@ -76,7 +76,7 @@ org.mockito - mockito-all + mockito-core test diff --git a/common/queue/pom.xml b/common/queue/pom.xml index 4c3eb4aeba..e0b30dd654 100644 --- a/common/queue/pom.xml +++ b/common/queue/pom.xml @@ -124,7 +124,7 @@ org.mockito - mockito-all + mockito-core test diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/azure/servicebus/TbServiceBusConsumerTemplate.java b/common/queue/src/main/java/org/thingsboard/server/queue/azure/servicebus/TbServiceBusConsumerTemplate.java index 5b562cbfbf..525f9bfe92 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/azure/servicebus/TbServiceBusConsumerTemplate.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/azure/servicebus/TbServiceBusConsumerTemplate.java @@ -154,6 +154,7 @@ public class TbServiceBusConsumerTemplate extends Abstract } private CompletableFuture> fromList(List> futures) { + @SuppressWarnings("unchecked") CompletableFuture>[] arrayFuture = new CompletableFuture[futures.size()]; futures.toArray(arrayFuture); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/memory/InMemoryStorage.java b/common/queue/src/main/java/org/thingsboard/server/queue/memory/InMemoryStorage.java index b46fd4c87d..226ed32682 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/memory/InMemoryStorage.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/memory/InMemoryStorage.java @@ -60,6 +60,7 @@ public final class InMemoryStorage { public List get(String topic) throws InterruptedException { if (storage.containsKey(topic)) { List entities; + @SuppressWarnings("unchecked") T first = (T) storage.get(topic).poll(); if (first != null) { entities = new ArrayList<>(); @@ -67,7 +68,9 @@ public final class InMemoryStorage { List otherList = new ArrayList<>(); storage.get(topic).drainTo(otherList, 999); for (TbQueueMsg other : otherList) { - entities.add((T) other); + @SuppressWarnings("unchecked") + T entity = (T) other; + entities.add(entity); } } else { entities = Collections.emptyList(); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/memory/InMemoryTbQueueConsumer.java b/common/queue/src/main/java/org/thingsboard/server/queue/memory/InMemoryTbQueueConsumer.java index 95af725bb4..6e28d48a4b 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/memory/InMemoryTbQueueConsumer.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/memory/InMemoryTbQueueConsumer.java @@ -64,6 +64,7 @@ public class InMemoryTbQueueConsumer implements TbQueueCon @Override public List poll(long durationInMillis) { if (subscribed) { + @SuppressWarnings("unchecked") List messages = partitions .stream() .map(tpi -> { diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageClient.java b/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageClient.java index 066475d5ba..01a322f158 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageClient.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageClient.java @@ -47,6 +47,7 @@ public class DefaultTbApiUsageClient implements TbApiUsageClient { @Value("${usage.stats.report.interval:10}") private int interval; + @SuppressWarnings("unchecked") private final ConcurrentMap[] values = new ConcurrentMap[ApiUsageRecordKey.values().length]; private final PartitionService partitionService; private final SchedulerComponent scheduler; diff --git a/common/stats/pom.xml b/common/stats/pom.xml index 205f5c1dc6..005c210b7b 100644 --- a/common/stats/pom.xml +++ b/common/stats/pom.xml @@ -79,7 +79,7 @@ org.mockito - mockito-all + mockito-core test @@ -89,4 +89,4 @@ - \ No newline at end of file + diff --git a/common/transport/coap/pom.xml b/common/transport/coap/pom.xml index a8a1ac452a..cea8ddc0ce 100644 --- a/common/transport/coap/pom.xml +++ b/common/transport/coap/pom.xml @@ -80,7 +80,7 @@ org.mockito - mockito-all + mockito-core test diff --git a/common/transport/http/pom.xml b/common/transport/http/pom.xml index 2c8a9bbeae..f229627480 100644 --- a/common/transport/http/pom.xml +++ b/common/transport/http/pom.xml @@ -73,7 +73,7 @@ org.mockito - mockito-all + mockito-core test diff --git a/common/transport/mqtt/pom.xml b/common/transport/mqtt/pom.xml index 18c2126f07..676593804e 100644 --- a/common/transport/mqtt/pom.xml +++ b/common/transport/mqtt/pom.xml @@ -90,7 +90,7 @@ org.mockito - mockito-all + mockito-core test diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttSslHandlerProvider.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttSslHandlerProvider.java index ec4247b718..c2cf3686e9 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttSslHandlerProvider.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttSslHandlerProvider.java @@ -45,6 +45,7 @@ import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.security.KeyStore; +import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.concurrent.CountDownLatch; @@ -154,7 +155,7 @@ public class MqttSslHandlerProvider { String credentialsBody = null; for (X509Certificate cert : chain) { try { - String strCert = SslUtil.getX509CertificateString(cert); + String strCert = SslUtil.getCertificateString(cert); String sha3Hash = EncryptionUtil.getSha3Hash(strCert); final String[] credentialsBodyHolder = new String[1]; CountDownLatch latch = new CountDownLatch(1); @@ -179,7 +180,7 @@ public class MqttSslHandlerProvider { credentialsBody = credentialsBodyHolder[0]; break; } - } catch (InterruptedException | IOException e) { + } catch (InterruptedException | CertificateEncodingException e) { log.error(e.getMessage(), e); } } diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java index 8a8fcff2a4..06a8dcacdc 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java @@ -35,6 +35,7 @@ import io.netty.handler.codec.mqtt.MqttSubscribeMessage; import io.netty.handler.codec.mqtt.MqttTopicSubscription; import io.netty.handler.codec.mqtt.MqttUnsubscribeMessage; import io.netty.handler.ssl.SslHandler; +import io.netty.util.CharsetUtil; import io.netty.util.ReferenceCountUtil; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.GenericFutureListener; @@ -68,7 +69,8 @@ import org.thingsboard.server.transport.mqtt.session.MqttTopicMatcher; import org.thingsboard.server.transport.mqtt.util.SslUtil; import javax.net.ssl.SSLPeerUnverifiedException; -import javax.security.cert.X509Certificate; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; import java.io.IOException; import java.net.InetSocketAddress; import java.util.ArrayList; @@ -315,7 +317,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement } private TransportServiceCallback getPubAckCallback(final ChannelHandlerContext ctx, final int msgId, final T msg) { - return new TransportServiceCallback() { + return new TransportServiceCallback<>() { @Override public void onSuccess(Void dummy) { log.trace("[{}] Published msg: {}", sessionId, msg); @@ -482,12 +484,13 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement if (userName != null) { request.setUserName(userName); } - String password = connectMessage.payload().password(); - if (password != null) { + byte[] passwordBytes = connectMessage.payload().passwordInBytes(); + if (passwordBytes != null) { + String password = new String(passwordBytes, CharsetUtil.UTF_8); request.setPassword(password); } transportService.process(DeviceTransportType.MQTT, request.build(), - new TransportServiceCallback() { + new TransportServiceCallback<>() { @Override public void onSuccess(ValidateDeviceCredentialsResponse msg) { onValidateDeviceResponse(msg, ctx, connectMessage); @@ -507,10 +510,10 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement if (!context.isSkipValidityCheckForClientCert()) { cert.checkValidity(); } - String strCert = SslUtil.getX509CertificateString(cert); + String strCert = SslUtil.getCertificateString(cert); String sha3Hash = EncryptionUtil.getSha3Hash(strCert); transportService.process(DeviceTransportType.MQTT, ValidateDeviceX509CertRequestMsg.newBuilder().setHash(sha3Hash).build(), - new TransportServiceCallback() { + new TransportServiceCallback<>() { @Override public void onSuccess(ValidateDeviceCredentialsResponse msg) { onValidateDeviceResponse(msg, ctx, connectMessage); @@ -531,9 +534,9 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement private X509Certificate getX509Certificate() { try { - X509Certificate[] certChain = sslHandler.engine().getSession().getPeerCertificateChain(); + Certificate[] certChain = sslHandler.engine().getSession().getPeerCertificates(); if (certChain.length > 0) { - return certChain[0]; + return (X509Certificate) certChain[0]; } } catch (SSLPeerUnverifiedException e) { log.warn(e.getMessage()); diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/util/SslUtil.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/util/SslUtil.java index bd0d034c35..f376077b84 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/util/SslUtil.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/util/SslUtil.java @@ -20,8 +20,8 @@ import org.springframework.util.Base64Utils; import org.thingsboard.server.common.msg.EncryptionUtil; import java.io.IOException; +import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; -import java.security.cert.X509Certificate; /** * @author Valerii Sosliuk @@ -32,15 +32,8 @@ public class SslUtil { private SslUtil() { } - public static String getX509CertificateString(X509Certificate cert) - throws CertificateEncodingException, IOException { - Base64Utils.encodeToString(cert.getEncoded()); - return EncryptionUtil.trimNewLines(Base64Utils.encodeToString(cert.getEncoded())); - } - - public static String getX509CertificateString(javax.security.cert.X509Certificate cert) - throws javax.security.cert.CertificateEncodingException, IOException { - Base64Utils.encodeToString(cert.getEncoded()); + public static String getCertificateString(Certificate cert) + throws CertificateEncodingException { return EncryptionUtil.trimNewLines(Base64Utils.encodeToString(cert.getEncoded())); } } diff --git a/common/transport/mqtt/src/test/java/org/thingsboard/server/transport/mqtt/util/MqttTopicFilterFactoryTest.java b/common/transport/mqtt/src/test/java/org/thingsboard/server/transport/mqtt/util/MqttTopicFilterFactoryTest.java index 178d174543..cc59d8bd0b 100644 --- a/common/transport/mqtt/src/test/java/org/thingsboard/server/transport/mqtt/util/MqttTopicFilterFactoryTest.java +++ b/common/transport/mqtt/src/test/java/org/thingsboard/server/transport/mqtt/util/MqttTopicFilterFactoryTest.java @@ -17,7 +17,7 @@ package org.thingsboard.server.transport.mqtt.util; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import javax.script.ScriptException; diff --git a/common/transport/transport-api/pom.xml b/common/transport/transport-api/pom.xml index 69a03dd170..60700bc3e7 100644 --- a/common/transport/transport-api/pom.xml +++ b/common/transport/transport-api/pom.xml @@ -87,7 +87,7 @@ org.mockito - mockito-all + mockito-core test diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/ProtoWithFSTService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/ProtoWithFSTService.java index 73ff79634d..a3b65c2248 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/ProtoWithFSTService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/ProtoWithFSTService.java @@ -32,6 +32,7 @@ public class ProtoWithFSTService implements DataDecodingEncodingService { @Override public Optional decode(byte[] byteArray) { try { + @SuppressWarnings("unchecked") T msg = (T) config.asObject(byteArray); return Optional.of(msg); } catch (IllegalArgumentException e) { diff --git a/common/util/pom.xml b/common/util/pom.xml index 68ad14d2eb..13afe4663a 100644 --- a/common/util/pom.xml +++ b/common/util/pom.xml @@ -41,6 +41,10 @@ guava provided + + javax.annotation + javax.annotation-api + org.slf4j slf4j-api @@ -64,7 +68,7 @@ org.mockito - mockito-all + mockito-core test diff --git a/dao/pom.xml b/dao/pom.xml index e9ee4e9219..cbd3899f25 100644 --- a/dao/pom.xml +++ b/dao/pom.xml @@ -92,7 +92,7 @@ org.mockito - mockito-all + mockito-core test diff --git a/dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java b/dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java index 445cf1c897..8f7071eadc 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java +++ b/dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java @@ -40,11 +40,11 @@ public abstract class DaoUtil { public static PageData toPageData(Page> page) { List data = convertDataList(page.getContent()); - return new PageData(data, page.getTotalPages(), page.getTotalElements(), page.hasNext()); + return new PageData<>(data, page.getTotalPages(), page.getTotalElements(), page.hasNext()); } public static PageData pageToPageData(Page page) { - return new PageData(page.getContent(), page.getTotalPages(), page.getTotalElements(), page.hasNext()); + return new PageData<>(page.getContent(), page.getTotalPages(), page.getTotalElements(), page.hasNext()); } public static Pageable toPageable(PageLink pageLink) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java index b239b8e9f8..9af4dc4749 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java @@ -306,7 +306,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ )); } return Futures.transform(Futures.successfulAsList(alarmFutures), - alarmInfos -> new PageData(alarmInfos, alarms.getTotalPages(), alarms.getTotalElements(), + alarmInfos -> new PageData<>(alarmInfos, alarms.getTotalPages(), alarms.getTotalElements(), alarms.hasNext()), MoreExecutors.directExecutor()); } return Futures.immediateFuture(alarms); diff --git a/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java index 8e0490b2c7..27eca316f9 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java @@ -190,6 +190,7 @@ public class AuditLogServiceImpl implements AuditLogService { case ATTRIBUTES_UPDATED: actionData.put("entityId", entityId.toString()); String scope = extractParameter(String.class, 0, additionalInfo); + @SuppressWarnings("unchecked") List attributes = extractParameter(List.class, 1, additionalInfo); actionData.put("scope", scope); ObjectNode attrsNode = JacksonUtil.newObjectNode(); @@ -205,6 +206,7 @@ public class AuditLogServiceImpl implements AuditLogService { actionData.put("entityId", entityId.toString()); scope = extractParameter(String.class, 0, additionalInfo); actionData.put("scope", scope); + @SuppressWarnings("unchecked") List keys = extractParameter(List.class, 1, additionalInfo); ArrayNode attrsArrayNode = actionData.putArray("attributes"); if (keys != null) { @@ -267,6 +269,7 @@ public class AuditLogServiceImpl implements AuditLogService { break; case TIMESERIES_UPDATED: actionData.put("entityId", entityId.toString()); + @SuppressWarnings("unchecked") List updatedTimeseries = extractParameter(List.class, 0, additionalInfo); if (updatedTimeseries != null) { ArrayNode result = actionData.putArray("timeseries"); @@ -283,6 +286,7 @@ public class AuditLogServiceImpl implements AuditLogService { break; case TIMESERIES_DELETED: actionData.put("entityId", entityId.toString()); + @SuppressWarnings("unchecked") List timeseriesKeys = extractParameter(List.class, 0, additionalInfo); if (timeseriesKeys != null) { ArrayNode timeseriesArrayNode = actionData.putArray("timeseries"); diff --git a/dao/src/main/java/org/thingsboard/server/dao/audit/DummyAuditLogServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/audit/DummyAuditLogServiceImpl.java index e19e580b9e..46190464db 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/audit/DummyAuditLogServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/audit/DummyAuditLogServiceImpl.java @@ -36,22 +36,22 @@ public class DummyAuditLogServiceImpl implements AuditLogService { @Override public PageData findAuditLogsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, List actionTypes, TimePageLink pageLink) { - return new PageData(); + return new PageData<>(); } @Override public PageData findAuditLogsByTenantIdAndUserId(TenantId tenantId, UserId userId, List actionTypes, TimePageLink pageLink) { - return new PageData(); + return new PageData<>(); } @Override public PageData findAuditLogsByTenantIdAndEntityId(TenantId tenantId, EntityId entityId, List actionTypes, TimePageLink pageLink) { - return new PageData(); + return new PageData<>(); } @Override public PageData findAuditLogsByTenantId(TenantId tenantId, List actionTypes, TimePageLink pageLink) { - return new PageData(); + return new PageData<>(); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java index db7dc6bd2d..5b6ae32437 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java @@ -275,6 +275,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti tenantIdAndEntityId.add(entityId); Cache cache = cacheManager.getCache(ENTITY_VIEW_CACHE); + @SuppressWarnings("unchecked") List fromCache = cache.get(tenantIdAndEntityId, List.class); if (fromCache != null) { return Futures.immediateFuture(fromCache); diff --git a/dao/src/main/java/org/thingsboard/server/dao/oauth2/HybridClientRegistrationRepository.java b/dao/src/main/java/org/thingsboard/server/dao/oauth2/HybridClientRegistrationRepository.java index 1639074338..7361dc21d2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/oauth2/HybridClientRegistrationRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/oauth2/HybridClientRegistrationRepository.java @@ -53,7 +53,7 @@ public class HybridClientRegistrationRepository implements ClientRegistrationRep .userNameAttributeName(localClientRegistration.getUserNameAttributeName()) .jwkSetUri(localClientRegistration.getJwkSetUri()) .clientAuthenticationMethod(new ClientAuthenticationMethod(localClientRegistration.getClientAuthenticationMethod())) - .redirectUriTemplate(defaultRedirectUriTemplate) + .redirectUri(defaultRedirectUriTemplate) .build(); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java index 9b936b94e8..1fa9f057b2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java @@ -301,6 +301,7 @@ public class BaseRelationService implements RelationService { fromAndTypeGroup.add(EntitySearchDirection.FROM.name()); Cache cache = cacheManager.getCache(RELATIONS_CACHE); + @SuppressWarnings("unchecked") List fromCache = cache.get(fromAndTypeGroup, List.class); if (fromCache != null) { return Futures.immediateFuture(fromCache); @@ -382,6 +383,7 @@ public class BaseRelationService implements RelationService { toAndTypeGroup.add(EntitySearchDirection.TO.name()); Cache cache = cacheManager.getCache(RELATIONS_CACHE); + @SuppressWarnings("unchecked") List fromCache = cache.get(toAndTypeGroup, List.class); if (fromCache != null) { return Futures.immediateFuture(fromCache); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/JpaDashboardInfoDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/JpaDashboardInfoDao.java index 3e6c5818ad..6d026327dd 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/JpaDashboardInfoDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/JpaDashboardInfoDao.java @@ -45,12 +45,12 @@ public class JpaDashboardInfoDao extends JpaAbstractSearchTextDao getEntityClass() { return DashboardInfoEntity.class; } @Override - protected CrudRepository getCrudRepository() { + protected CrudRepository getCrudRepository() { return dashboardInfoRepository; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceProfileDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceProfileDao.java index 70136aa216..92085d44f4 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceProfileDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceProfileDao.java @@ -15,7 +15,7 @@ */ package org.thingsboard.server.dao.sql.device; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Component; diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/RelationRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/RelationRepository.java index a27b39ced0..c5a1774ae6 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/RelationRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/RelationRepository.java @@ -49,7 +49,7 @@ public interface RelationRepository String fromType); @Transactional - RelationEntity save(RelationEntity entity); + S save(S entity); @Transactional void deleteById(RelationCompositeKey id); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java index 0a750778e3..66907fea5f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java @@ -39,12 +39,12 @@ public class JpaRuleChainDao extends JpaAbstractSearchTextDao getEntityClass() { return RuleChainEntity.class; } @Override - protected CrudRepository getCrudRepository() { + protected CrudRepository getCrudRepository() { return ruleChainRepository; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeDao.java index b99d26ebe0..362299f9b3 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeDao.java @@ -24,6 +24,8 @@ import org.thingsboard.server.dao.model.sql.RuleNodeEntity; import org.thingsboard.server.dao.rule.RuleNodeDao; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; +import java.util.UUID; + @Slf4j @Component public class JpaRuleNodeDao extends JpaAbstractSearchTextDao implements RuleNodeDao { @@ -32,12 +34,12 @@ public class JpaRuleNodeDao extends JpaAbstractSearchTextDao getEntityClass() { return RuleNodeEntity.class; } @Override - protected CrudRepository getCrudRepository() { + protected CrudRepository getCrudRepository() { return ruleNodeRepository; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeStateDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeStateDao.java index 3f1647b155..2be895bf86 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeStateDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeStateDao.java @@ -39,12 +39,12 @@ public class JpaRuleNodeStateDao extends JpaAbstractDao getEntityClass() { return RuleNodeStateEntity.class; } @Override - protected CrudRepository getCrudRepository() { + protected CrudRepository getCrudRepository() { return ruleNodeStateRepository; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleNodeRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleNodeRepository.java index 4bf2f48a85..09e4bb55ae 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleNodeRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleNodeRepository.java @@ -18,6 +18,8 @@ package org.thingsboard.server.dao.sql.rule; import org.springframework.data.repository.CrudRepository; import org.thingsboard.server.dao.model.sql.RuleNodeEntity; -public interface RuleNodeRepository extends CrudRepository { +import java.util.UUID; + +public interface RuleNodeRepository extends CrudRepository { } diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java index f0888055f2..2f817634c3 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java @@ -32,6 +32,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.env.Environment; +import org.springframework.core.env.Profiles; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; @@ -108,7 +109,7 @@ public class CassandraBaseTimeseriesDao extends AbstractCassandraBaseTimeseriesD private PreparedStatement deletePartitionStmt; private boolean isInstall() { - return environment.acceptsProfiles("install"); + return environment.acceptsProfiles(Profiles.of("install")); } @PostConstruct diff --git a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java index 519092274b..4efff2582e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java @@ -15,8 +15,8 @@ */ package org.thingsboard.server.dao.user; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; @@ -48,6 +48,7 @@ import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.dao.tenant.TenantDao; +import org.thingsboard.server.dao.util.mapping.JacksonUtil; import java.util.HashMap; import java.util.Map; @@ -71,8 +72,6 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic private static final String USER_CREDENTIALS_ENABLED = "userCredentialsEnabled"; - private static final ObjectMapper objectMapper = new ObjectMapper(); - @Value("${security.user_login_case_sensitive:true}") private boolean userLoginCaseSensitive; @@ -279,7 +278,7 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic User user = findUserById(tenantId, userId); JsonNode additionalInfo = user.getAdditionalInfo(); if (!(additionalInfo instanceof ObjectNode)) { - additionalInfo = objectMapper.createObjectNode(); + additionalInfo = JacksonUtil.newObjectNode(); } ((ObjectNode) additionalInfo).put(USER_CREDENTIALS_ENABLED, enabled); user.setAdditionalInfo(additionalInfo); @@ -302,7 +301,7 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic private void setLastLoginTs(User user) { JsonNode additionalInfo = user.getAdditionalInfo(); if (!(additionalInfo instanceof ObjectNode)) { - additionalInfo = objectMapper.createObjectNode(); + additionalInfo = JacksonUtil.newObjectNode(); } ((ObjectNode) additionalInfo).put(LAST_LOGIN_TS, System.currentTimeMillis()); user.setAdditionalInfo(additionalInfo); @@ -311,7 +310,7 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic private void resetFailedLoginAttempts(User user) { JsonNode additionalInfo = user.getAdditionalInfo(); if (!(additionalInfo instanceof ObjectNode)) { - additionalInfo = objectMapper.createObjectNode(); + additionalInfo = JacksonUtil.newObjectNode(); } ((ObjectNode) additionalInfo).put(FAILED_LOGIN_ATTEMPTS, 0); user.setAdditionalInfo(additionalInfo); @@ -329,7 +328,7 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic private int increaseFailedLoginAttempts(User user) { JsonNode additionalInfo = user.getAdditionalInfo(); if (!(additionalInfo instanceof ObjectNode)) { - additionalInfo = objectMapper.createObjectNode(); + additionalInfo = JacksonUtil.newObjectNode(); } int failedLoginAttempts = 0; if (additionalInfo.has(FAILED_LOGIN_ATTEMPTS)) { @@ -353,26 +352,30 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic private void updatePasswordHistory(User user, UserCredentials userCredentials) { JsonNode additionalInfo = user.getAdditionalInfo(); if (!(additionalInfo instanceof ObjectNode)) { - additionalInfo = objectMapper.createObjectNode(); + additionalInfo = JacksonUtil.newObjectNode(); } + Map userPasswordHistoryMap = null; + JsonNode userPasswordHistoryJson; if (additionalInfo.has(USER_PASSWORD_HISTORY)) { - JsonNode userPasswordHistoryJson = additionalInfo.get(USER_PASSWORD_HISTORY); - Map userPasswordHistoryMap = objectMapper.convertValue(userPasswordHistoryJson, Map.class); + userPasswordHistoryJson = additionalInfo.get(USER_PASSWORD_HISTORY); + userPasswordHistoryMap = JacksonUtil.convertValue(userPasswordHistoryJson, new TypeReference<>(){}); + } + if (userPasswordHistoryMap != null) { userPasswordHistoryMap.put(Long.toString(System.currentTimeMillis()), userCredentials.getPassword()); - userPasswordHistoryJson = objectMapper.valueToTree(userPasswordHistoryMap); + userPasswordHistoryJson = JacksonUtil.valueToTree(userPasswordHistoryMap); ((ObjectNode) additionalInfo).replace(USER_PASSWORD_HISTORY, userPasswordHistoryJson); } else { - Map userPasswordHistoryMap = new HashMap<>(); + userPasswordHistoryMap = new HashMap<>(); userPasswordHistoryMap.put(Long.toString(System.currentTimeMillis()), userCredentials.getPassword()); - JsonNode userPasswordHistoryJson = objectMapper.valueToTree(userPasswordHistoryMap); + userPasswordHistoryJson = JacksonUtil.valueToTree(userPasswordHistoryMap); ((ObjectNode) additionalInfo).set(USER_PASSWORD_HISTORY, userPasswordHistoryJson); } user.setAdditionalInfo(additionalInfo); saveUser(user); } - private DataValidator userValidator = - new DataValidator() { + private final DataValidator userValidator = + new DataValidator<>() { @Override protected void validateCreate(TenantId tenantId, User user) { if (!user.getTenantId().getId().equals(ModelConstants.NULL_UUID)) { @@ -452,8 +455,8 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic } }; - private DataValidator userCredentialsValidator = - new DataValidator() { + private final DataValidator userCredentialsValidator = + new DataValidator<>() { @Override protected void validateCreate(TenantId tenantId, UserCredentials userCredentials) { @@ -484,7 +487,7 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic } }; - private PaginatedRemover tenantAdminsRemover = new PaginatedRemover() { + private final PaginatedRemover tenantAdminsRemover = new PaginatedRemover<>() { @Override protected PageData findEntities(TenantId tenantId, TenantId id, PageLink pageLink) { return userDao.findTenantAdmins(id.getId(), pageLink); @@ -496,7 +499,7 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic } }; - private PaginatedRemover customerUsersRemover = new PaginatedRemover() { + private final PaginatedRemover customerUsersRemover = new PaginatedRemover<>() { @Override protected PageData findEntities(TenantId tenantId, CustomerId id, PageLink pageLink) { return userDao.findCustomerUsers(tenantId.getId(), id.getId(), pageLink); diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/mapping/JacksonUtil.java b/dao/src/main/java/org/thingsboard/server/dao/util/mapping/JacksonUtil.java index 1a56ff54e1..43c7318470 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/util/mapping/JacksonUtil.java +++ b/dao/src/main/java/org/thingsboard/server/dao/util/mapping/JacksonUtil.java @@ -16,6 +16,7 @@ package org.thingsboard.server.dao.util.mapping; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -38,6 +39,15 @@ public class JacksonUtil { } } + public static T convertValue(Object fromValue, TypeReference toValueTypeRef) { + try { + return fromValue != null ? OBJECT_MAPPER.convertValue(fromValue, toValueTypeRef) : null; + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException("The given object value: " + + fromValue + " cannot be converted to " + toValueTypeRef, e); + } + } + public static T fromString(String string, Class clazz) { try { return string != null ? OBJECT_MAPPER.readValue(string, clazz) : null; @@ -72,7 +82,9 @@ public class JacksonUtil { } public static T clone(T value) { - return fromString(toString(value), (Class) value.getClass()); + @SuppressWarnings("unchecked") + Class valueClass = (Class) value.getClass(); + return fromString(toString(value), valueClass); } public static JsonNode valueToTree(T value) { diff --git a/dao/src/test/java/org/apache/cassandra/io/sstable/Descriptor.java b/dao/src/test/java/org/apache/cassandra/io/sstable/Descriptor.java index a5e6122537..69a164f729 100644 --- a/dao/src/test/java/org/apache/cassandra/io/sstable/Descriptor.java +++ b/dao/src/test/java/org/apache/cassandra/io/sstable/Descriptor.java @@ -244,6 +244,7 @@ public class Descriptor * * @return A Descriptor for the SSTable, and the Component remainder. */ + @SuppressWarnings("deprecation") public static Pair fromFilename(File directory, String name, boolean skipComponent) { File parentDirectory = directory != null ? directory : new File("."); @@ -319,6 +320,7 @@ public class Descriptor component); } + @SuppressWarnings("deprecation") public IMetadataSerializer getMetadataSerializer() { if (version.hasNewStatsFile()) diff --git a/dao/src/test/java/org/apache/cassandra/io/sstable/format/SSTableFormat.java b/dao/src/test/java/org/apache/cassandra/io/sstable/format/SSTableFormat.java index af6af442a3..350d27591f 100644 --- a/dao/src/test/java/org/apache/cassandra/io/sstable/format/SSTableFormat.java +++ b/dao/src/test/java/org/apache/cassandra/io/sstable/format/SSTableFormat.java @@ -56,6 +56,7 @@ public interface SSTableFormat return BIG; } + @SuppressWarnings("deprecation") private Type(String name, SSTableFormat info) { //Since format comes right after generation diff --git a/dao/src/test/java/org/apache/cassandra/io/util/FileUtils.java b/dao/src/test/java/org/apache/cassandra/io/util/FileUtils.java new file mode 100644 index 0000000000..2609a2c3d0 --- /dev/null +++ b/dao/src/test/java/org/apache/cassandra/io/util/FileUtils.java @@ -0,0 +1,760 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cassandra.io.util; + +import java.io.*; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.*; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.FileAttributeView; +import java.nio.file.attribute.FileStoreAttributeView; +import java.text.DecimalFormat; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.stream.StreamSupport; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.cassandra.concurrent.ScheduledExecutors; +import org.apache.cassandra.io.FSError; +import org.apache.cassandra.io.FSErrorHandler; +import org.apache.cassandra.io.FSReadError; +import org.apache.cassandra.io.FSWriteError; +import org.apache.cassandra.io.sstable.CorruptSSTableException; +import org.apache.cassandra.utils.JVMStabilityInspector; + +import static com.google.common.base.Throwables.throwIfUnchecked; +import static org.apache.cassandra.utils.Throwables.maybeFail; +import static org.apache.cassandra.utils.Throwables.merge; + +public final class FileUtils +{ + public static final Charset CHARSET = StandardCharsets.UTF_8; + + private static final Logger logger = LoggerFactory.getLogger(FileUtils.class); + public static final long ONE_KB = 1024; + public static final long ONE_MB = 1024 * ONE_KB; + public static final long ONE_GB = 1024 * ONE_MB; + public static final long ONE_TB = 1024 * ONE_GB; + + private static final DecimalFormat df = new DecimalFormat("#.##"); + public static final boolean isCleanerAvailable = false; + private static final AtomicReference> fsErrorHandler = new AtomicReference<>(Optional.empty()); + + public static void createHardLink(String from, String to) + { + createHardLink(new File(from), new File(to)); + } + + public static void createHardLink(File from, File to) + { + if (to.exists()) + throw new RuntimeException("Tried to create duplicate hard link to " + to); + if (!from.exists()) + throw new RuntimeException("Tried to hard link to file that does not exist " + from); + + try + { + Files.createLink(to.toPath(), from.toPath()); + } + catch (IOException e) + { + throw new FSWriteError(e, to); + } + } + + public static File createTempFile(String prefix, String suffix, File directory) + { + try + { + return File.createTempFile(prefix, suffix, directory); + } + catch (IOException e) + { + throw new FSWriteError(e, directory); + } + } + + public static File createTempFile(String prefix, String suffix) + { + return createTempFile(prefix, suffix, new File(System.getProperty("java.io.tmpdir"))); + } + + public static Throwable deleteWithConfirm(String filePath, boolean expect, Throwable accumulate) + { + return deleteWithConfirm(new File(filePath), expect, accumulate); + } + + public static Throwable deleteWithConfirm(File file, boolean expect, Throwable accumulate) + { + boolean exists = file.exists(); + assert exists || !expect : "attempted to delete non-existing file " + file.getName(); + try + { + if (exists) + Files.delete(file.toPath()); + } + catch (Throwable t) + { + try + { + throw new FSWriteError(t, file); + } + catch (Throwable t2) + { + accumulate = merge(accumulate, t2); + } + } + return accumulate; + } + + public static void deleteWithConfirm(String file) + { + deleteWithConfirm(new File(file)); + } + + public static void deleteWithConfirm(File file) + { + maybeFail(deleteWithConfirm(file, true, null)); + } + + public static void renameWithOutConfirm(String from, String to) + { + try + { + atomicMoveWithFallback(new File(from).toPath(), new File(to).toPath()); + } + catch (IOException e) + { + if (logger.isTraceEnabled()) + logger.trace("Could not move file "+from+" to "+to, e); + } + } + + public static void renameWithConfirm(String from, String to) + { + renameWithConfirm(new File(from), new File(to)); + } + + public static void renameWithConfirm(File from, File to) + { + assert from.exists(); + if (logger.isTraceEnabled()) + logger.trace("Renaming {} to {}", from.getPath(), to.getPath()); + // this is not FSWE because usually when we see it it's because we didn't close the file before renaming it, + // and Windows is picky about that. + try + { + atomicMoveWithFallback(from.toPath(), to.toPath()); + } + catch (IOException e) + { + throw new RuntimeException(String.format("Failed to rename %s to %s", from.getPath(), to.getPath()), e); + } + } + + /** + * Move a file atomically, if it fails, it falls back to a non-atomic operation + * @param from + * @param to + * @throws IOException + */ + private static void atomicMoveWithFallback(Path from, Path to) throws IOException + { + try + { + Files.move(from, to, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); + } + catch (AtomicMoveNotSupportedException e) + { + logger.trace("Could not do an atomic move", e); + Files.move(from, to, StandardCopyOption.REPLACE_EXISTING); + } + + } + public static void truncate(String path, long size) + { + try(FileChannel channel = FileChannel.open(Paths.get(path), StandardOpenOption.READ, StandardOpenOption.WRITE)) + { + channel.truncate(size); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + public static void closeQuietly(Closeable c) + { + try + { + if (c != null) + c.close(); + } + catch (Exception e) + { + logger.warn("Failed closing {}", c, e); + } + } + + public static void closeQuietly(AutoCloseable c) + { + try + { + if (c != null) + c.close(); + } + catch (Exception e) + { + logger.warn("Failed closing {}", c, e); + } + } + + public static void close(Closeable... cs) throws IOException + { + close(Arrays.asList(cs)); + } + + public static void close(Iterable cs) throws IOException + { + Throwable e = null; + for (Closeable c : cs) + { + try + { + if (c != null) + c.close(); + } + catch (Throwable ex) + { + if (e == null) e = ex; + else e.addSuppressed(ex); + logger.warn("Failed closing stream {}", c, ex); + } + } + maybeFail(e, IOException.class); + } + + public static void closeQuietly(Iterable cs) + { + for (AutoCloseable c : cs) + { + try + { + if (c != null) + c.close(); + } + catch (Exception ex) + { + logger.warn("Failed closing {}", c, ex); + } + } + } + + public static String getCanonicalPath(String filename) + { + try + { + return new File(filename).getCanonicalPath(); + } + catch (IOException e) + { + throw new FSReadError(e, filename); + } + } + + public static String getCanonicalPath(File file) + { + try + { + return file.getCanonicalPath(); + } + catch (IOException e) + { + throw new FSReadError(e, file); + } + } + + /** Return true if file is contained in folder */ + public static boolean isContained(File folder, File file) + { + Path folderPath = Paths.get(getCanonicalPath(folder)); + Path filePath = Paths.get(getCanonicalPath(file)); + + return filePath.startsWith(folderPath); + } + + /** Convert absolute path into a path relative to the base path */ + public static String getRelativePath(String basePath, String path) + { + try + { + return Paths.get(basePath).relativize(Paths.get(path)).toString(); + } + catch(Exception ex) + { + String absDataPath = FileUtils.getCanonicalPath(basePath); + return Paths.get(absDataPath).relativize(Paths.get(path)).toString(); + } + } + + public static void clean(ByteBuffer buffer) + { + if (buffer == null) + return; + } + + public static void createDirectory(String directory) + { + createDirectory(new File(directory)); + } + + public static void createDirectory(File directory) + { + if (!directory.exists()) + { + if (!directory.mkdirs()) + throw new FSWriteError(new IOException("Failed to mkdirs " + directory), directory); + } + } + + public static boolean delete(String file) + { + File f = new File(file); + return f.delete(); + } + + public static void delete(File... files) + { + if (files == null) + { + // CASSANDRA-13389: some callers use Files.listFiles() which, on error, silently returns null + logger.debug("Received null list of files to delete"); + return; + } + + for ( File file : files ) + { + file.delete(); + } + } + + public static void deleteAsync(final String file) + { + Runnable runnable = new Runnable() + { + public void run() + { + deleteWithConfirm(new File(file)); + } + }; + ScheduledExecutors.nonPeriodicTasks.execute(runnable); + } + + public static void visitDirectory(Path dir, Predicate filter, Consumer consumer) + { + try (DirectoryStream stream = Files.newDirectoryStream(dir)) + { + StreamSupport.stream(stream.spliterator(), false) + .map(Path::toFile) + // stream directories are weakly consistent so we always check if the file still exists + .filter(f -> f.exists() && (filter == null || filter.test(f))) + .forEach(consumer); + } + catch (IOException|DirectoryIteratorException ex) + { + logger.error("Failed to list files in {} with exception: {}", dir, ex.getMessage(), ex); + } + } + + public static String stringifyFileSize(double value) + { + double d; + if ( value >= ONE_TB ) + { + d = value / ONE_TB; + String val = df.format(d); + return val + " TiB"; + } + else if ( value >= ONE_GB ) + { + d = value / ONE_GB; + String val = df.format(d); + return val + " GiB"; + } + else if ( value >= ONE_MB ) + { + d = value / ONE_MB; + String val = df.format(d); + return val + " MiB"; + } + else if ( value >= ONE_KB ) + { + d = value / ONE_KB; + String val = df.format(d); + return val + " KiB"; + } + else + { + String val = df.format(value); + return val + " bytes"; + } + } + + /** + * Deletes all files and subdirectories under "dir". + * @param dir Directory to be deleted + * @throws FSWriteError if any part of the tree cannot be deleted + */ + public static void deleteRecursive(File dir) + { + if (dir.isDirectory()) + { + String[] children = dir.list(); + for (String child : children) + deleteRecursive(new File(dir, child)); + } + + // The directory is now empty so now it can be smoked + deleteWithConfirm(dir); + } + + /** + * Schedules deletion of all file and subdirectories under "dir" on JVM shutdown. + * @param dir Directory to be deleted + */ + public static void deleteRecursiveOnExit(File dir) + { + if (dir.isDirectory()) + { + String[] children = dir.list(); + for (String child : children) + deleteRecursiveOnExit(new File(dir, child)); + } + + logger.trace("Scheduling deferred deletion of file: {}", dir); + dir.deleteOnExit(); + } + + public static void handleCorruptSSTable(CorruptSSTableException e) + { + fsErrorHandler.get().ifPresent(handler -> handler.handleCorruptSSTable(e)); + } + + public static void handleFSError(FSError e) + { + fsErrorHandler.get().ifPresent(handler -> handler.handleFSError(e)); + } + + /** + * handleFSErrorAndPropagate will invoke the disk failure policy error handler, + * which may or may not stop the daemon or transports. However, if we don't exit, + * we still want to propagate the exception to the caller in case they have custom + * exception handling + * + * @param e A filesystem error + */ + public static void handleFSErrorAndPropagate(FSError e) + { + JVMStabilityInspector.inspectThrowable(e); + throwIfUnchecked(e); + throw new RuntimeException(e); + } + + /** + * Get the size of a directory in bytes + * @param folder The directory for which we need size. + * @return The size of the directory + */ + public static long folderSize(File folder) + { + final long [] sizeArr = {0L}; + try + { + Files.walkFileTree(folder.toPath(), new SimpleFileVisitor() + { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) + { + sizeArr[0] += attrs.size(); + return FileVisitResult.CONTINUE; + } + }); + } + catch (IOException e) + { + logger.error("Error while getting {} folder size. {}", folder, e); + } + return sizeArr[0]; + } + + public static void copyTo(DataInput in, OutputStream out, int length) throws IOException + { + byte[] buffer = new byte[64 * 1024]; + int copiedBytes = 0; + + while (copiedBytes + buffer.length < length) + { + in.readFully(buffer); + out.write(buffer); + copiedBytes += buffer.length; + } + + if (copiedBytes < length) + { + int left = length - copiedBytes; + in.readFully(buffer, 0, left); + out.write(buffer, 0, left); + } + } + + public static boolean isSubDirectory(File parent, File child) throws IOException + { + parent = parent.getCanonicalFile(); + child = child.getCanonicalFile(); + + File toCheck = child; + while (toCheck != null) + { + if (parent.equals(toCheck)) + return true; + toCheck = toCheck.getParentFile(); + } + return false; + } + + public static void append(File file, String ... lines) + { + if (file.exists()) + write(file, Arrays.asList(lines), StandardOpenOption.APPEND); + else + write(file, Arrays.asList(lines), StandardOpenOption.CREATE); + } + + public static void appendAndSync(File file, String ... lines) + { + if (file.exists()) + write(file, Arrays.asList(lines), StandardOpenOption.APPEND, StandardOpenOption.SYNC); + else + write(file, Arrays.asList(lines), StandardOpenOption.CREATE, StandardOpenOption.SYNC); + } + + public static void replace(File file, String ... lines) + { + write(file, Arrays.asList(lines), StandardOpenOption.TRUNCATE_EXISTING); + } + + public static void write(File file, List lines, StandardOpenOption ... options) + { + try + { + Files.write(file.toPath(), + lines, + CHARSET, + options); + } + catch (IOException ex) + { + throw new RuntimeException(ex); + } + } + + public static List readLines(File file) + { + try + { + return Files.readAllLines(file.toPath(), CHARSET); + } + catch (IOException ex) + { + if (ex instanceof NoSuchFileException) + return Collections.emptyList(); + + throw new RuntimeException(ex); + } + } + + public static void setFSErrorHandler(FSErrorHandler handler) + { + fsErrorHandler.getAndSet(Optional.ofNullable(handler)); + } + + /** + * Returns the size of the specified partition. + *

This method handles large file system by returning {@code Long.MAX_VALUE} if the size overflow. + * See JDK-8179320 for more information.

+ * + * @param file the partition + * @return the size, in bytes, of the partition or {@code 0L} if the abstract pathname does not name a partition + */ + public static long getTotalSpace(File file) + { + return handleLargeFileSystem(file.getTotalSpace()); + } + + /** + * Returns the number of unallocated bytes on the specified partition. + *

This method handles large file system by returning {@code Long.MAX_VALUE} if the number of unallocated bytes + * overflow. See JDK-8179320 for more information

+ * + * @param file the partition + * @return the number of unallocated bytes on the partition or {@code 0L} + * if the abstract pathname does not name a partition. + */ + public static long getFreeSpace(File file) + { + return handleLargeFileSystem(file.getFreeSpace()); + } + + /** + * Returns the number of available bytes on the specified partition. + *

This method handles large file system by returning {@code Long.MAX_VALUE} if the number of available bytes + * overflow. See JDK-8179320 for more information

+ * + * @param file the partition + * @return the number of available bytes on the partition or {@code 0L} + * if the abstract pathname does not name a partition. + */ + public static long getUsableSpace(File file) + { + return handleLargeFileSystem(file.getUsableSpace()); + } + + /** + * Returns the {@link FileStore} representing the file store where a file + * is located. This {@link FileStore} handles large file system by returning {@code Long.MAX_VALUE} + * from {@code FileStore#getTotalSpace()}, {@code FileStore#getUnallocatedSpace()} and {@code FileStore#getUsableSpace()} + * it the value is bigger than {@code Long.MAX_VALUE}. See JDK-8162520 + * for more information. + * + * @param path the path to the file + * @return the file store where the file is stored + */ + public static FileStore getFileStore(Path path) throws IOException + { + return new SafeFileStore(Files.getFileStore(path)); + } + + /** + * Handle large file system by returning {@code Long.MAX_VALUE} when the size overflows. + * @param size returned by the Java's FileStore methods + * @return the size or {@code Long.MAX_VALUE} if the size was bigger than {@code Long.MAX_VALUE} + */ + private static long handleLargeFileSystem(long size) + { + return size < 0 ? Long.MAX_VALUE : size; + } + + /** + * Private constructor as the class contains only static methods. + */ + private FileUtils() + { + } + + /** + * FileStore decorator used to safely handle large file system. + * + *

Java's FileStore methods (getTotalSpace/getUnallocatedSpace/getUsableSpace) are limited to reporting bytes as + * signed long (2^63-1), if the filesystem is any bigger, then the size overflows. {@code SafeFileStore} will + * return {@code Long.MAX_VALUE} if the size overflow.

+ * + * @see https://bugs.openjdk.java.net/browse/JDK-8162520. + */ + private static final class SafeFileStore extends FileStore + { + /** + * The decorated {@code FileStore} + */ + private final FileStore fileStore; + + public SafeFileStore(FileStore fileStore) + { + this.fileStore = fileStore; + } + + @Override + public String name() + { + return fileStore.name(); + } + + @Override + public String type() + { + return fileStore.type(); + } + + @Override + public boolean isReadOnly() + { + return fileStore.isReadOnly(); + } + + @Override + public long getTotalSpace() throws IOException + { + return handleLargeFileSystem(fileStore.getTotalSpace()); + } + + @Override + public long getUsableSpace() throws IOException + { + return handleLargeFileSystem(fileStore.getUsableSpace()); + } + + @Override + public long getUnallocatedSpace() throws IOException + { + return handleLargeFileSystem(fileStore.getUnallocatedSpace()); + } + + @Override + public boolean supportsFileAttributeView(Class type) + { + return fileStore.supportsFileAttributeView(type); + } + + @Override + public boolean supportsFileAttributeView(String name) + { + return fileStore.supportsFileAttributeView(name); + } + + @Override + public V getFileStoreAttributeView(Class type) + { + return fileStore.getFileStoreAttributeView(type); + } + + @Override + public Object getAttribute(String attribute) throws IOException + { + return fileStore.getAttribute(attribute); + } + } +} diff --git a/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java b/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java index 5530bdbcb2..d3c6c97367 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java @@ -25,7 +25,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Spy; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import org.springframework.core.env.Environment; import org.springframework.test.util.ReflectionTestUtils; import org.thingsboard.server.common.data.id.TenantId; @@ -35,9 +35,9 @@ import org.thingsboard.server.dao.timeseries.CassandraBaseTimeseriesDao; import java.util.UUID; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyString; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java index a885ac38de..3fd416f28c 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java @@ -347,7 +347,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { } private AlarmDataQuery toQuery(AlarmDataPageLink pageLink){ - return toQuery(pageLink, Collections.EMPTY_LIST); + return toQuery(pageLink, Collections.emptyList()); } private AlarmDataQuery toQuery(AlarmDataPageLink pageLink, List alarmFields){ diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseEntityServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseEntityServiceTest.java index 7c7a3fa3d7..d3c2deefba 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseEntityServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseEntityServiceTest.java @@ -1193,7 +1193,7 @@ public abstract class BaseEntityServiceTest extends AbstractServiceTest { EntityDataPageLink pageLink = new EntityDataPageLink(100, 0, null, sortOrder); EntityDataQuery query = new EntityDataQuery(filter, pageLink, entityFields, null, deviceTypeFilters); - PageData data = entityService.findEntityDataByQuery(tenantId, new CustomerId(CustomerId.NULL_UUID), query); + PageData data = entityService.findEntityDataByQuery(tenantId, new CustomerId(CustomerId.NULL_UUID), query); List loadedEntities = getLoadedEntities(data, query); Assert.assertEquals(devices.size(), loadedEntities.size()); @@ -1220,7 +1220,7 @@ public abstract class BaseEntityServiceTest extends AbstractServiceTest { return A.containsAll(B) && B.containsAll(A); } - private List getLoadedEntities(PageData data, EntityDataQuery query) { + private List getLoadedEntities(PageData data, EntityDataQuery query) { List loadedEntities = new ArrayList<>(data.getData()); while (data.hasNext()) { diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/AbstractContainerTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/AbstractContainerTest.java index e17e5d0261..412cf3094b 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/AbstractContainerTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/AbstractContainerTest.java @@ -51,6 +51,7 @@ import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.msa.mapper.WsTelemetryResponse; +import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocket; @@ -114,14 +115,17 @@ public abstract class AbstractContainerTest { } protected Device createDevice(String name) { - return restClient.createDevice(name + RandomStringUtils.randomAlphanumeric(7), "DEFAULT"); + Device device = new Device(); + device.setName(name + RandomStringUtils.randomAlphanumeric(7)); + device.setType("DEFAULT"); + return restClient.saveDevice(device); } protected WsClient subscribeToWebSocket(DeviceId deviceId, String scope, CmdsType property) throws Exception { WsClient wsClient = new WsClient(new URI(WSS_URL + "/api/ws/plugins/telemetry?token=" + restClient.getToken())); SSLContextBuilder builder = SSLContexts.custom(); builder.loadTrustMaterial(null, (TrustStrategy) (chain, authType) -> true); - wsClient.setSocket(builder.build().getSocketFactory().createSocket()); + wsClient.setSocketFactory(builder.build().getSocketFactory()); wsClient.connectBlocking(); JsonObject cmdsObject = new JsonObject(); @@ -218,24 +222,7 @@ public abstract class AbstractContainerTest { SSLContextBuilder builder = SSLContexts.custom(); builder.loadTrustMaterial(null, (TrustStrategy) (chain, authType) -> true); SSLContext sslContext = builder.build(); - SSLConnectionSocketFactory sslSelfSigned = new SSLConnectionSocketFactory(sslContext, new X509HostnameVerifier() { - @Override - public void verify(String host, SSLSocket ssl) { - } - - @Override - public void verify(String host, X509Certificate cert) { - } - - @Override - public void verify(String host, String[] cns, String[] subjectAlts) { - } - - @Override - public boolean verify(String s, SSLSession sslSession) { - return true; - } - }); + SSLConnectionSocketFactory sslSelfSigned = new SSLConnectionSocketFactory(sslContext, (s, sslSession) -> true); Registry socketFactoryRegistry = RegistryBuilder .create() diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ContainerTestSuite.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ContainerTestSuite.java index 78e94d001c..acaf417882 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ContainerTestSuite.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ContainerTestSuite.java @@ -34,7 +34,7 @@ import java.util.Map; @ClasspathSuite.ClassnameFilters({"org.thingsboard.server.msa.*Test"}) public class ContainerTestSuite { - private static DockerComposeContainer testContainer; + private static DockerComposeContainer testContainer; @ClassRule public static ThingsBoardDbInstaller installTb = new ThingsBoardDbInstaller(); @@ -43,7 +43,7 @@ public class ContainerTestSuite { public static DockerComposeContainer getTestContainer() { if (testContainer == null) { boolean skipTailChildContainers = Boolean.valueOf(System.getProperty("blackBoxTests.skipTailChildContainers")); - testContainer = new DockerComposeContainer( + testContainer = new DockerComposeContainer<>( new File("./../../docker/docker-compose.yml"), new File("./../../docker/docker-compose.postgres.yml"), new File("./../../docker/docker-compose.postgres.volumes.yml"), diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/HttpClientTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/HttpClientTest.java index 0d20661b25..855d2a926c 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/HttpClientTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/HttpClientTest.java @@ -44,7 +44,7 @@ public class HttpClientTest extends AbstractContainerTest { restClient.login("tenant@thingsboard.org", "tenant"); Device device = createDevice("http_"); - DeviceCredentials deviceCredentials = restClient.getCredentials(device.getId()); + DeviceCredentials deviceCredentials = restClient.getDeviceCredentialsByDeviceId(device.getId()).get(); WsClient wsClient = subscribeToWebSocket(device.getId(), "LATEST_TELEMETRY", CmdsType.TS_SUB_CMDS); ResponseEntity deviceTelemetryResponse = restClient.getRestTemplate() @@ -73,7 +73,7 @@ public class HttpClientTest extends AbstractContainerTest { TB_TOKEN = restClient.getToken(); Device device = createDevice("test"); - String accessToken = restClient.getCredentials(device.getId()).getCredentialsId(); + String accessToken = restClient.getDeviceCredentialsByDeviceId(device.getId()).get().getCredentialsId(); assertNotNull(accessToken); ResponseEntity deviceSharedAttributes = restClient.getRestTemplate() @@ -92,6 +92,7 @@ public class HttpClientTest extends AbstractContainerTest { TimeUnit.SECONDS.sleep(3); + @SuppressWarnings("deprecation") Optional allOptional = restClient.getAttributes(accessToken, null, null); assertTrue(allOptional.isPresent()); @@ -101,6 +102,7 @@ public class HttpClientTest extends AbstractContainerTest { assertEquals(mapper.readTree(createPayload().toString()), all.get("shared")); assertEquals(mapper.readTree(createPayload().toString()), all.get("client")); + @SuppressWarnings("deprecation") Optional sharedOptional = restClient.getAttributes(accessToken, null, "stringKey"); assertTrue(sharedOptional.isPresent()); @@ -108,6 +110,7 @@ public class HttpClientTest extends AbstractContainerTest { assertEquals(shared.get("shared").get("stringKey"), mapper.readTree(createPayload().get("stringKey").toString())); assertFalse(shared.has("client")); + @SuppressWarnings("deprecation") Optional clientOptional = restClient.getAttributes(accessToken, "longKey,stringKey", null); assertTrue(clientOptional.isPresent()); diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttClientTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttClientTest.java index f3212a53cc..c8156b6ef1 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttClientTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttClientTest.java @@ -62,7 +62,7 @@ public class MqttClientTest extends AbstractContainerTest { public void telemetryUpload() throws Exception { restClient.login("tenant@thingsboard.org", "tenant"); Device device = createDevice("mqtt_"); - DeviceCredentials deviceCredentials = restClient.getCredentials(device.getId()); + DeviceCredentials deviceCredentials = restClient.getDeviceCredentialsByDeviceId(device.getId()).get(); WsClient wsClient = subscribeToWebSocket(device.getId(), "LATEST_TELEMETRY", CmdsType.TS_SUB_CMDS); MqttClient mqttClient = getMqttClient(deviceCredentials, null); @@ -89,7 +89,7 @@ public class MqttClientTest extends AbstractContainerTest { restClient.login("tenant@thingsboard.org", "tenant"); Device device = createDevice("mqtt_"); - DeviceCredentials deviceCredentials = restClient.getCredentials(device.getId()); + DeviceCredentials deviceCredentials = restClient.getDeviceCredentialsByDeviceId(device.getId()).get(); WsClient wsClient = subscribeToWebSocket(device.getId(), "LATEST_TELEMETRY", CmdsType.TS_SUB_CMDS); MqttClient mqttClient = getMqttClient(deviceCredentials, null); @@ -113,7 +113,7 @@ public class MqttClientTest extends AbstractContainerTest { public void publishAttributeUpdateToServer() throws Exception { restClient.login("tenant@thingsboard.org", "tenant"); Device device = createDevice("mqtt_"); - DeviceCredentials deviceCredentials = restClient.getCredentials(device.getId()); + DeviceCredentials deviceCredentials = restClient.getDeviceCredentialsByDeviceId(device.getId()).get(); WsClient wsClient = subscribeToWebSocket(device.getId(), "CLIENT_SCOPE", CmdsType.ATTR_SUB_CMDS); MqttMessageListener listener = new MqttMessageListener(); @@ -144,7 +144,7 @@ public class MqttClientTest extends AbstractContainerTest { public void requestAttributeValuesFromServer() throws Exception { restClient.login("tenant@thingsboard.org", "tenant"); Device device = createDevice("mqtt_"); - DeviceCredentials deviceCredentials = restClient.getCredentials(device.getId()); + DeviceCredentials deviceCredentials = restClient.getDeviceCredentialsByDeviceId(device.getId()).get(); WsClient wsClient = subscribeToWebSocket(device.getId(), "CLIENT_SCOPE", CmdsType.ATTR_SUB_CMDS); MqttMessageListener listener = new MqttMessageListener(); @@ -204,7 +204,7 @@ public class MqttClientTest extends AbstractContainerTest { public void subscribeToAttributeUpdatesFromServer() throws Exception { restClient.login("tenant@thingsboard.org", "tenant"); Device device = createDevice("mqtt_"); - DeviceCredentials deviceCredentials = restClient.getCredentials(device.getId()); + DeviceCredentials deviceCredentials = restClient.getDeviceCredentialsByDeviceId(device.getId()).get(); MqttMessageListener listener = new MqttMessageListener(); MqttClient mqttClient = getMqttClient(deviceCredentials, listener); @@ -250,7 +250,7 @@ public class MqttClientTest extends AbstractContainerTest { public void serverSideRpc() throws Exception { restClient.login("tenant@thingsboard.org", "tenant"); Device device = createDevice("mqtt_"); - DeviceCredentials deviceCredentials = restClient.getCredentials(device.getId()); + DeviceCredentials deviceCredentials = restClient.getDeviceCredentialsByDeviceId(device.getId()).get(); MqttMessageListener listener = new MqttMessageListener(); MqttClient mqttClient = getMqttClient(deviceCredentials, listener); @@ -297,7 +297,7 @@ public class MqttClientTest extends AbstractContainerTest { public void clientSideRpc() throws Exception { restClient.login("tenant@thingsboard.org", "tenant"); Device device = createDevice("mqtt_"); - DeviceCredentials deviceCredentials = restClient.getCredentials(device.getId()); + DeviceCredentials deviceCredentials = restClient.getDeviceCredentialsByDeviceId(device.getId()).get(); MqttMessageListener listener = new MqttMessageListener(); MqttClient mqttClient = getMqttClient(deviceCredentials, listener); diff --git a/netty-mqtt/pom.xml b/netty-mqtt/pom.xml index 46ab5af314..3cf567a26f 100644 --- a/netty-mqtt/pom.xml +++ b/netty-mqtt/pom.xml @@ -67,16 +67,15 @@ org.apache.maven.plugins maven-compiler-plugin - 3.1 + 3.8.1 - 1.8 - 1.8 + 11 org.apache.maven.plugins maven-jar-plugin - 2.4 + 3.1.1 @@ -87,4 +86,4 @@ - \ No newline at end of file + diff --git a/pom.xml b/pom.xml index 83899b46cb..9f77ec04b0 100755 --- a/pom.xml +++ b/pom.xml @@ -36,6 +36,9 @@ ${project.name} /var/log/${pkg.name} /usr/share/${pkg.name} + 1.3.2 + 2.3.2 + 2.3.2 2.3.5.RELEASE 5.2.10.RELEASE 5.4.1 @@ -46,9 +49,9 @@ 4.12 1.7.7 1.2.3 - 1.9.5 + 3.3.3 0.10 - 4.6.0 + 4.10.0 4.0.5 4.3.1.0 3.11.9 @@ -70,7 +73,7 @@ 3.5.5 3.11.4 1.22.1 - 1.16.18 + 1.18.18 1.2.4 4.1.53.Final 1.5.0 @@ -86,12 +89,12 @@ 2.5.0 2.5.3 1.2.1 - 9.4.1212 + 42.2.16 org/thingsboard/server/gen/**/*, org/thingsboard/server/extensions/core/plugin/telemetry/gen/**/* 5.0.2 - 0.1.14 + 0.1.31 2.6.0 4.1.1 2.57 @@ -543,10 +546,14 @@ org.apache.maven.plugins maven-compiler-plugin - 2.5.1 + 3.8.1 - 1.8 - 1.8 + 11 + + -Xlint:deprecation + -Xlint:removal + -Xlint:unchecked + @@ -557,18 +564,23 @@ org.apache.maven.plugins maven-source-plugin - 2.2.1 + 3.2.1 org.apache.maven.plugins maven-jar-plugin - 3.0.2 + 3.1.1 org.apache.maven.plugins maven-assembly-plugin 3.0.0 + + org.apache.maven.plugins + maven-deploy-plugin + 2.8.2 + org.springframework.boot spring-boot-maven-plugin @@ -583,6 +595,11 @@ org.apache.maven.plugins maven-surefire-plugin 3.0.0-M1 + + + --illegal-access=permit + + org.apache.maven.plugins @@ -872,6 +889,21 @@ test-jar test
+ + javax.annotation + javax.annotation-api + ${javax-annotation.version} + + + jakarta.xml.bind + jakarta.xml.bind-api + ${jakarta.xml.bind-api.version} + + + org.glassfish.jaxb + jaxb-runtime + ${jaxb-runtime.version} + org.springframework.boot spring-boot-starter-security @@ -1219,7 +1251,7 @@ org.mockito - mockito-all + mockito-core ${mockito.version} test diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java index d7188f4456..7a7319f742 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java @@ -225,9 +225,6 @@ public interface TbContext { TbResultSetFuture submitCassandraTask(CassandraStatementTask task); - @Deprecated - RedisTemplate getRedisTemplate(); - PageData findRuleNodeStates(PageLink pageLink); RuleNodeState findRuleNodeStateForEntity(EntityId entityId); diff --git a/rule-engine/rule-engine-components/pom.xml b/rule-engine/rule-engine-components/pom.xml index 0084e0e531..31c0c1d824 100644 --- a/rule-engine/rule-engine-components/pom.xml +++ b/rule-engine/rule-engine-components/pom.xml @@ -148,7 +148,7 @@ org.mockito - mockito-all + mockito-core test diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractCustomerActionNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractCustomerActionNode.java index 482e5261f0..30f3c59873 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractCustomerActionNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractCustomerActionNode.java @@ -48,7 +48,7 @@ public abstract class TbAbstractCustomerActionNode cacheBuilder = CacheBuilder.newBuilder(); if (this.config.getCustomerCacheExpiration() > 0) { cacheBuilder.expireAfterWrite(this.config.getCustomerCacheExpiration(), TimeUnit.SECONDS); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractRelationActionNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractRelationActionNode.java index 66a8f28e87..afa04236b5 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractRelationActionNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractRelationActionNode.java @@ -70,7 +70,7 @@ public abstract class TbAbstractRelationActionNode cacheBuilder = CacheBuilder.newBuilder(); if (this.config.getEntityCacheExpiration() > 0) { cacheBuilder.expireAfterWrite(this.config.getEntityCacheExpiration(), TimeUnit.SECONDS); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/GeoUtil.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/GeoUtil.java index 6ce7de8baf..b5612dfc6a 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/GeoUtil.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/GeoUtil.java @@ -62,7 +62,7 @@ public class GeoUtil { } polygonBuilder.pointXY(jtsCtx.getShapeFactory().normX(firstLng), jtsCtx.getShapeFactory().normY(firstLat)); Shape shape = polygonBuilder.buildOrRect(); - Point point = jtsCtx.makePoint(coordinates.getLongitude(), coordinates.getLatitude()); + Point point = jtsCtx.getShapeFactory().pointXY(coordinates.getLongitude(), coordinates.getLatitude()); return shape.relate(point).equals(SpatialRelation.CONTAINS); } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/EmailPojo.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/EmailPojo.java index cce9ab0b3e..b8339f2f86 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/EmailPojo.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/EmailPojo.java @@ -15,11 +15,15 @@ */ package org.thingsboard.rule.engine.mail; +import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; @Data @Builder +@AllArgsConstructor +@NoArgsConstructor(force = true) class EmailPojo { private final String from; diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java index 5788b2e086..879cdd76e6 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java @@ -17,6 +17,7 @@ package org.thingsboard.rule.engine.metadata; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.json.JsonWriteFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.Futures; @@ -61,7 +62,7 @@ public abstract class TbAbstractGetAttributesNode) invocationOnMock -> (Alarm) (invocationOnMock.getArguments())[0]).when(alarmService).createOrUpdateAlarm(activeAlarm); @@ -346,7 +346,7 @@ public class TbAlarmNodeTest { when(detailsJs.executeJsonAsync(msg)).thenReturn(Futures.immediateFuture(null)); when(alarmService.findAlarmByIdAsync(tenantId, id)).thenReturn(Futures.immediateFuture(activeAlarm)); - when(alarmService.clearAlarm(eq(activeAlarm.getTenantId()), eq(activeAlarm.getId()), org.mockito.Mockito.any(JsonNode.class), anyLong())).thenReturn(Futures.immediateFuture(true)); + when(alarmService.clearAlarm(eq(activeAlarm.getTenantId()), eq(activeAlarm.getId()), nullable(JsonNode.class), anyLong())).thenReturn(Futures.immediateFuture(true)); // doAnswer((Answer) invocationOnMock -> (Alarm) (invocationOnMock.getArguments())[0]).when(alarmService).createOrUpdateAlarm(activeAlarm); node.onMsg(ctx, msg); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeTest.java index 0c0f49f298..0f5dfb6ee7 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeTest.java @@ -22,10 +22,9 @@ import com.google.common.util.concurrent.ListenableFuture; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; -import org.mockito.Matchers; +import org.mockito.ArgumentMatchers; import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import org.mockito.stubbing.Answer; import org.thingsboard.common.util.ListeningExecutor; import org.thingsboard.rule.engine.api.ScriptEngine; @@ -66,7 +65,6 @@ public class TbJsFilterNodeTest { public void falseEvaluationDoNotSendMsg() throws TbNodeException, ScriptException { initWithScript(); TbMsg msg = TbMsg.newMsg("USER", null, new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - mockJsExecutor(); when(scriptEngine.executeFilterAsync(msg)).thenReturn(Futures.immediateFuture(false)); node.onMsg(ctx, msg); @@ -79,7 +77,6 @@ public class TbJsFilterNodeTest { initWithScript(); TbMsgMetaData metaData = new TbMsgMetaData(); TbMsg msg = TbMsg.newMsg("USER", null, metaData, TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - mockJsExecutor(); when(scriptEngine.executeFilterAsync(msg)).thenReturn(Futures.immediateFailedFuture(new ScriptException("error"))); @@ -92,7 +89,6 @@ public class TbJsFilterNodeTest { initWithScript(); TbMsgMetaData metaData = new TbMsgMetaData(); TbMsg msg = TbMsg.newMsg("USER", null, metaData, TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - mockJsExecutor(); when(scriptEngine.executeFilterAsync(msg)).thenReturn(Futures.immediateFuture(true)); node.onMsg(ctx, msg); @@ -112,18 +108,6 @@ public class TbJsFilterNodeTest { node.init(ctx, nodeConfiguration); } - private void mockJsExecutor() { - when(ctx.getJsExecutor()).thenReturn(executor); - doAnswer((Answer>) invocationOnMock -> { - try { - Callable task = (Callable) (invocationOnMock.getArguments())[0]; - return Futures.immediateFuture((Boolean) task.call()); - } catch (Throwable th) { - return Futures.immediateFailedFuture(th); - } - }).when(executor).executeAsync(Matchers.any(Callable.class)); - } - private void verifyError(TbMsg msg, String message, Class expectedClass) { ArgumentCaptor captor = ArgumentCaptor.forClass(Throwable.class); verify(ctx).tellFailure(same(msg), captor.capture()); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsSwitchNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsSwitchNodeTest.java index 5609345ac8..cfacf4cb85 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsSwitchNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsSwitchNodeTest.java @@ -23,9 +23,9 @@ import com.google.common.util.concurrent.ListenableFuture; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; -import org.mockito.Matchers; +import org.mockito.ArgumentMatchers; import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import org.mockito.stubbing.Answer; import org.thingsboard.common.util.ListeningExecutor; import org.thingsboard.rule.engine.api.ScriptEngine; @@ -43,7 +43,7 @@ import java.util.Set; import java.util.concurrent.Callable; import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.same; +import static org.mockito.ArgumentMatchers.same; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -92,6 +92,7 @@ public class TbJsSwitchNodeTest { node.init(ctx, nodeConfiguration); } + @SuppressWarnings("unchecked") private void mockJsExecutor() { when(ctx.getJsExecutor()).thenReturn(executor); doAnswer((Answer>>) invocationOnMock -> { @@ -101,7 +102,7 @@ public class TbJsSwitchNodeTest { } catch (Throwable th) { return Futures.immediateFailedFuture(th); } - }).when(executor).executeAsync(Matchers.any(Callable.class)); + }).when(executor).executeAsync(ArgumentMatchers.any(Callable.class)); } private void verifyError(TbMsg msg, String message, Class expectedClass) { diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNodeTest.java index 4ded096fb5..3385d20d3a 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNodeTest.java @@ -21,7 +21,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java index 1d811b4ef9..ca88290808 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java @@ -24,7 +24,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; @@ -58,13 +58,12 @@ import java.util.Map; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Matchers.same; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.same; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.thingsboard.rule.engine.api.TbRelationTypes.FAILURE; -import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS; import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; @RunWith(MockitoJUnitRunner.class) diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeTest.java index ef8c1c5558..912fee62c2 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeTest.java @@ -23,7 +23,7 @@ import org.junit.runner.RunWith; import org.mockito.AdditionalAnswers; import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import org.thingsboard.rule.engine.api.RuleEngineAlarmService; import org.thingsboard.rule.engine.api.RuleEngineDeviceProfileCache; import org.thingsboard.rule.engine.api.TbContext; diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNodeTest.java index 772c17d790..10202e2a68 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNodeTest.java @@ -24,7 +24,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import org.thingsboard.common.util.ListeningExecutor; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeConfiguration; @@ -43,9 +43,9 @@ import org.thingsboard.server.dao.asset.AssetService; import java.util.concurrent.Callable; import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Matchers.same; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.same; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.thingsboard.rule.engine.api.TbRelationTypes.FAILURE; diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbTransformMsgNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbTransformMsgNodeTest.java index 62558f25d1..ca6a4f8c02 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbTransformMsgNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbTransformMsgNodeTest.java @@ -22,9 +22,9 @@ import com.google.common.util.concurrent.ListenableFuture; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; -import org.mockito.Matchers; +import org.mockito.ArgumentMatchers; import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import org.mockito.stubbing.Answer; import org.thingsboard.common.util.ListeningExecutor; import org.thingsboard.rule.engine.api.ScriptEngine; @@ -42,12 +42,10 @@ import java.util.Collections; import java.util.concurrent.Callable; import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.same; +import static org.mockito.ArgumentMatchers.same; import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS; @RunWith(MockitoJUnitRunner.class) public class TbTransformMsgNodeTest { @@ -72,7 +70,6 @@ public class TbTransformMsgNodeTest { RuleNodeId ruleNodeId = new RuleNodeId(Uuids.timeBased()); TbMsg msg = TbMsg.newMsg( "USER", null, metaData, TbMsgDataType.JSON,rawJson, ruleChainId, ruleNodeId); TbMsg transformedMsg = TbMsg.newMsg( "USER", null, metaData, TbMsgDataType.JSON, "{new}", ruleChainId, ruleNodeId); - mockJsExecutor(); when(scriptEngine.executeUpdateAsync(msg)).thenReturn(Futures.immediateFuture(Collections.singletonList(transformedMsg))); node.onMsg(ctx, msg); @@ -93,7 +90,6 @@ public class TbTransformMsgNodeTest { RuleChainId ruleChainId = new RuleChainId(Uuids.timeBased()); RuleNodeId ruleNodeId = new RuleNodeId(Uuids.timeBased()); TbMsg msg = TbMsg.newMsg( "USER", null, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); - mockJsExecutor(); when(scriptEngine.executeUpdateAsync(msg)).thenReturn(Futures.immediateFailedFuture(new IllegalStateException("error"))); node.onMsg(ctx, msg); @@ -112,18 +108,6 @@ public class TbTransformMsgNodeTest { node.init(ctx, nodeConfiguration); } - private void mockJsExecutor() { - when(ctx.getJsExecutor()).thenReturn(executor); - doAnswer((Answer>) invocationOnMock -> { - try { - Callable task = (Callable) (invocationOnMock.getArguments())[0]; - return Futures.immediateFuture((TbMsg) task.call()); - } catch (Throwable th) { - return Futures.immediateFailedFuture(th); - } - }).when(executor).executeAsync(Matchers.any(Callable.class)); - } - private void verifyError(TbMsg msg, String message, Class expectedClass) { ArgumentCaptor captor = ArgumentCaptor.forClass(Throwable.class); verify(ctx).tellFailure(same(msg), captor.capture()); diff --git a/transport/coap/pom.xml b/transport/coap/pom.xml index 440be0ecea..1ede01a491 100644 --- a/transport/coap/pom.xml +++ b/transport/coap/pom.xml @@ -76,7 +76,7 @@ org.mockito - mockito-all + mockito-core test diff --git a/transport/http/pom.xml b/transport/http/pom.xml index bb9262de66..41ca5683a1 100644 --- a/transport/http/pom.xml +++ b/transport/http/pom.xml @@ -76,7 +76,7 @@ org.mockito - mockito-all + mockito-core test diff --git a/transport/mqtt/pom.xml b/transport/mqtt/pom.xml index 579d514729..28aaeeab39 100644 --- a/transport/mqtt/pom.xml +++ b/transport/mqtt/pom.xml @@ -76,7 +76,7 @@ org.mockito - mockito-all + mockito-core test From 03fa7dcd416552d8ed0e42492dc557d5643bce27 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Fri, 5 Feb 2021 11:50:35 +0200 Subject: [PATCH 117/249] Do not use dashboard state param from url location inside embed dashboard dialog --- .../dashboard-page.component.html | 1 + .../dashboard-page.component.ts | 3 ++ .../states/state-controller.component.ts | 46 +++++++++++-------- .../states/state-controller.models.ts | 1 + .../states/states-component.directive.ts | 6 +++ .../embed-dashboard-dialog.component.html | 3 +- 6 files changed, 39 insertions(+), 21 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html index 5ba7f2f01c..77e6047d8a 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html @@ -53,6 +53,7 @@ [isMobile]="isMobile" [state]="dashboardCtx.state" [currentState]="currentState" + [syncStateWithQueryParam]="syncStateWithQueryParam" [states]="dashboardConfiguration.states">
diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts index 31fb065a83..5385913842 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts @@ -123,6 +123,9 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC @Input() hideToolbar: boolean; + @Input() + syncStateWithQueryParam = true; + @Input() dashboard: Dashboard; dashboardConfiguration: DashboardConfiguration; diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/states/state-controller.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/states/state-controller.component.ts index 61eaa6ae5c..cd54ec7558 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/states/state-controller.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/states/state-controller.component.ts @@ -88,6 +88,8 @@ export abstract class StateControllerComponent implements IStateControllerCompon currentState: string; + syncStateWithQueryParam: boolean; + private rxSubscriptions = new Array(); private inited = false; @@ -99,18 +101,20 @@ export abstract class StateControllerComponent implements IStateControllerCompon } ngOnInit(): void { - this.rxSubscriptions.push(this.route.queryParamMap.subscribe((paramMap) => { - const dashboardId = this.route.snapshot.params.dashboardId || ''; - if (this.dashboardId === dashboardId) { - const newState = this.decodeStateParam(paramMap.get('state')); - if (this.currentState !== newState) { - this.currentState = newState; - if (this.inited) { - this.onStateChanged(); + if (this.syncStateWithQueryParam) { + this.rxSubscriptions.push(this.route.queryParamMap.subscribe((paramMap) => { + const dashboardId = this.route.snapshot.params.dashboardId || ''; + if (this.dashboardId === dashboardId) { + const newState = this.decodeStateParam(paramMap.get('state')); + if (this.currentState !== newState) { + this.currentState = newState; + if (this.inited) { + this.onStateChanged(); + } } } - } - })); + })); + } this.init(); this.inited = true; } @@ -124,16 +128,18 @@ export abstract class StateControllerComponent implements IStateControllerCompon protected updateStateParam(newState: string) { this.currentState = newState; - const queryParams: Params = { state: this.currentState }; - this.ngZone.run(() => { - this.router.navigate( - [], - { - relativeTo: this.route, - queryParams, - queryParamsHandling: 'merge', - }); - }); + if (this.syncStateWithQueryParam) { + const queryParams: Params = {state: this.currentState}; + this.ngZone.run(() => { + this.router.navigate( + [], + { + relativeTo: this.route, + queryParams, + queryParamsHandling: 'merge', + }); + }); + } } public openRightLayout(): void { diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/states/state-controller.models.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/states/state-controller.models.ts index 730f31dd0b..6a21ac564f 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/states/state-controller.models.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/states/state-controller.models.ts @@ -24,6 +24,7 @@ export interface IStateControllerComponent extends IStateController { stateControllerInstanceId: string; state: string; currentState: string; + syncStateWithQueryParam: boolean; isMobile: boolean; states: {[id: string]: DashboardState }; dashboardId: string; diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/states/states-component.directive.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/states/states-component.directive.ts index e377f77fff..b6911ed9d8 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/states/states-component.directive.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/states/states-component.directive.ts @@ -53,6 +53,9 @@ export class StatesComponentDirective implements OnInit, OnDestroy, OnChanges { @Input() currentState: string; + @Input() + syncStateWithQueryParam: boolean; + @Input() isMobile: boolean; @@ -89,6 +92,8 @@ export class StatesComponentDirective implements OnInit, OnDestroy, OnChanges { this.stateControllerComponent.state = this.state; } else if (propName === 'currentState') { this.stateControllerComponent.currentState = this.currentState; + } else if (propName === 'syncStateWithQueryParam') { + this.stateControllerComponent.syncStateWithQueryParam = this.syncStateWithQueryParam; } } } @@ -119,6 +124,7 @@ export class StatesComponentDirective implements OnInit, OnDestroy, OnChanges { this.stateControllerComponent.stateControllerInstanceId = stateControllerInstanceId; this.stateControllerComponent.state = this.state; this.stateControllerComponent.currentState = this.currentState; + this.stateControllerComponent.syncStateWithQueryParam = this.syncStateWithQueryParam; this.stateControllerComponent.isMobile = this.isMobile; this.stateControllerComponent.states = this.states; this.stateControllerComponent.dashboardId = this.dashboardId; diff --git a/ui-ngx/src/app/modules/home/components/widget/dialog/embed-dashboard-dialog.component.html b/ui-ngx/src/app/modules/home/components/widget/dialog/embed-dashboard-dialog.component.html index 04bc5708b6..ca4f2a56b7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/dialog/embed-dashboard-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/dialog/embed-dashboard-dialog.component.html @@ -27,7 +27,8 @@
- +