iotagent-node-lib 3.2.0 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.yml +134 -0
  2. package/.github/ISSUE_TEMPLATE/config.yml +16 -0
  3. package/.github/ISSUE_TEMPLATE/feature_request.yml +55 -0
  4. package/.github/advanced-issue-labeler.yml +30 -0
  5. package/.github/workflows/issue-labeler.yml +43 -0
  6. package/doc/api.md +23 -80
  7. package/doc/deprecated.md +4 -0
  8. package/doc/howto.md +58 -62
  9. package/doc/installationguide.md +0 -5
  10. package/doc/requirements.txt +1 -1
  11. package/docker/Mosquitto/Dockerfile +1 -1
  12. package/lib/model/Device.js +0 -1
  13. package/lib/model/Group.js +0 -1
  14. package/lib/model/dbConn.js +1 -7
  15. package/lib/plugins/jexlParser.js +1 -1
  16. package/lib/services/common/iotManagerService.js +0 -1
  17. package/lib/services/devices/deviceRegistryMongoDB.js +10 -10
  18. package/lib/services/devices/deviceService.js +14 -19
  19. package/lib/services/devices/devices-NGSI-v2.js +2 -5
  20. package/lib/services/ngsi/entities-NGSI-LD.js +3 -3
  21. package/lib/services/ngsi/entities-NGSI-v2.js +34 -11
  22. package/lib/services/northBound/deviceProvisioningServer.js +0 -3
  23. package/lib/templates/createDevice.json +0 -4
  24. package/lib/templates/createDeviceLax.json +0 -4
  25. package/lib/templates/deviceGroup.json +1 -5
  26. package/lib/templates/updateDevice.json +4 -0
  27. package/lib/templates/updateDeviceLax.json +11 -0
  28. package/package.json +1 -1
  29. package/scripts/legacy_expression_tool/README.md +262 -0
  30. package/scripts/legacy_expression_tool/legacy_expression_tool.py +423 -0
  31. package/scripts/legacy_expression_tool/requirements.txt +3 -0
  32. package/test/unit/examples/deviceProvisioningRequests/provisionMinimumDevice4.json +0 -1
  33. package/test/unit/general/contextBrokerKeystoneSecurityAccess-test.js +3 -13
  34. package/test/unit/ngsi-ld/lazyAndCommands/merge-patch-test.js +31 -30
  35. package/test/unit/ngsi-mixed/provisioning/ngsi-versioning-test.js +33 -37
  36. package/test/unit/ngsiv2/examples/contextRequests/updateContext.json +2 -0
  37. package/test/unit/ngsiv2/examples/contextRequests/updateContext1.json +3 -1
  38. package/test/unit/ngsiv2/examples/contextRequests/updateContext3WithStatic.json +2 -0
  39. package/test/unit/ngsiv2/examples/contextRequests/updateContext4.json +4 -1
  40. package/test/unit/ngsiv2/examples/contextRequests/updateContext5.json +12 -0
  41. package/test/unit/ngsiv2/examples/contextRequests/updateContext6.json +10 -0
  42. package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin1.json +2 -0
  43. package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin2.json +3 -1
  44. package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin3.json +3 -1
  45. package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin4.json +3 -1
  46. package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin5.json +3 -1
  47. package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin6.json +3 -1
  48. package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin7.json +3 -1
  49. package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin8.json +3 -1
  50. package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin9.json +3 -1
  51. package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast1.json +2 -0
  52. package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast2.json +2 -0
  53. package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast3.json +3 -1
  54. package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast4.json +3 -1
  55. package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast5.json +3 -1
  56. package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast6.json +3 -1
  57. package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast7.json +3 -1
  58. package/test/unit/ngsiv2/examples/contextRequests/updateContextCommandError.json +3 -1
  59. package/test/unit/ngsiv2/examples/contextRequests/updateContextCommandExpired.json +3 -1
  60. package/test/unit/ngsiv2/examples/contextRequests/updateContextCommandFinish.json +3 -1
  61. package/test/unit/ngsiv2/examples/contextRequests/updateContextCommandStatus.json +2 -0
  62. package/test/unit/ngsiv2/examples/contextRequests/updateContextCommandStatus2.json +2 -0
  63. package/test/unit/ngsiv2/examples/contextRequests/updateContextCompressTimestamp1.json +3 -1
  64. package/test/unit/ngsiv2/examples/contextRequests/updateContextCompressTimestamp2.json +3 -1
  65. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin1.json +2 -0
  66. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin11.json +2 -0
  67. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin12.json +2 -0
  68. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin13.json +3 -1
  69. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin2.json +2 -0
  70. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin29.json +2 -0
  71. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin3.json +2 -0
  72. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin30.json +2 -0
  73. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin31.json +2 -0
  74. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin32.json +2 -0
  75. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin33.json +2 -0
  76. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin34.json +2 -0
  77. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin35.json +2 -0
  78. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin36.json +1 -0
  79. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin4.json +2 -0
  80. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin40.json +1 -1
  81. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin41.json +1 -0
  82. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin5.json +2 -0
  83. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin6.json +2 -0
  84. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin7.json +2 -0
  85. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin8.json +2 -0
  86. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin9.json +2 -0
  87. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionSkip.json +12 -0
  88. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityJexlExpressionPlugin1.json +1 -1
  89. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin1.json +1 -1
  90. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin10.json +1 -1
  91. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin11.json +1 -1
  92. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin12.json +1 -1
  93. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin13.json +1 -1
  94. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin14.json +1 -1
  95. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin15.json +1 -1
  96. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin16.json +1 -1
  97. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin17.json +1 -1
  98. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin2.json +1 -1
  99. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin25.json +1 -1
  100. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin3.json +1 -1
  101. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin4.json +1 -1
  102. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin5.json +1 -1
  103. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin6.json +1 -1
  104. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin7.json +1 -1
  105. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin8.json +1 -1
  106. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin9.json +1 -1
  107. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin1.json +1 -1
  108. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin2.json +1 -1
  109. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin3.json +1 -1
  110. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin4.json +2 -0
  111. package/test/unit/ngsiv2/examples/contextRequests/updateContextProcessTimestamp.json +2 -0
  112. package/test/unit/ngsiv2/examples/contextRequests/updateContextStaticAttributes.json +2 -0
  113. package/test/unit/ngsiv2/examples/contextRequests/updateContextStaticAttributesMetadata.json +3 -1
  114. package/test/unit/ngsiv2/examples/contextRequests/updateContextTimestamp.json +3 -1
  115. package/test/unit/ngsiv2/examples/contextRequests/updateContextTimestampFalse.json +12 -0
  116. package/test/unit/ngsiv2/examples/contextRequests/updateContextTimestampFalseTimeInstant.json +12 -0
  117. package/test/unit/ngsiv2/examples/contextRequests/updateContextTimestampOverride.json +2 -0
  118. package/test/unit/ngsiv2/examples/contextRequests/updateContextTimestampOverrideWithoutMilis.json +2 -0
  119. package/test/unit/ngsiv2/examples/contextRequests/updateContextTimestampTimezone.json +3 -1
  120. package/test/unit/ngsiv2/expressions/jexlBasedTransformations-test.js +133 -75
  121. package/test/unit/ngsiv2/general/contextBrokerOAuthSecurityAccess-test.js +18 -51
  122. package/test/unit/ngsiv2/general/https-support-test.js +1 -5
  123. package/test/unit/ngsiv2/lazyAndCommands/command-test.js +4 -10
  124. package/test/unit/ngsiv2/lazyAndCommands/polling-commands-test.js +8 -24
  125. package/test/unit/ngsiv2/ngsiService/active-devices-test.js +143 -57
  126. package/test/unit/ngsiv2/ngsiService/autocast-test.js +14 -21
  127. package/test/unit/ngsiv2/ngsiService/staticAttributes-test.js +3 -5
  128. package/test/unit/ngsiv2/ngsiService/subscriptions-test.js +1 -10
  129. package/test/unit/ngsiv2/plugins/alias-plugin_test.js +20 -30
  130. package/test/unit/ngsiv2/plugins/bidirectional-plugin_test.js +0 -63
  131. package/test/unit/ngsiv2/plugins/compress-timestamp-plugin_test.js +4 -6
  132. package/test/unit/ngsiv2/plugins/custom-plugin_test.js +1 -2
  133. package/test/unit/ngsiv2/plugins/multientity-plugin_test.js +3 -5
  134. package/test/unit/ngsiv2/plugins/timestamp-processing-plugin_test.js +2 -3
  135. package/test/unit/ngsiv2/provisioning/device-group-api-test.js +2 -3
  136. package/test/unit/ngsiv2/provisioning/device-provisioning-api_test.js +5 -53
  137. package/test/unit/ngsiv2/provisioning/device-registration_test.js +1 -7
  138. package/test/unit/ngsiv2/provisioning/device-update-registration_test.js +2 -9
  139. package/test/unit/ngsiv2/provisioning/singleConfigurationMode-test.js +0 -11
  140. package/test/unit/ngsiv2/provisioning/updateProvisionedDevices-test.js +0 -7
  141. package/test/unit/plugins/capture-provision-inPlugins_test.js +0 -6
package/doc/howto.md CHANGED
@@ -75,12 +75,12 @@ folder of your project. Remember to change the Context Broker IP to your local C
75
75
  Now we can begin with the code of our IoT Agent. The very minimum code we need to start an IoT Agent is the following:
76
76
 
77
77
  ```javascript
78
- var iotAgentLib = require("iotagent-node-lib"),
79
- config = require("./config");
78
+ var iotAgentLib = require('iotagent-node-lib'),
79
+ config = require('./config');
80
80
 
81
81
  iotAgentLib.activate(config, function (error) {
82
82
  if (error) {
83
- console.log("There was an error activating the IOTA");
83
+ console.log('There was an error activating the IOTA');
84
84
  process.exit(1);
85
85
  }
86
86
  });
@@ -112,10 +112,10 @@ In order to add the Express dependency to your project, add the following line t
112
112
  The require section would end up like this (the standard `http` module is also needed):
113
113
 
114
114
  ```javascript
115
- var iotAgentLib = require("iotagent-node-lib"),
116
- http = require("http"),
117
- express = require("express"),
118
- config = require("./config");
115
+ var iotAgentLib = require('iotagent-node-lib'),
116
+ http = require('http'),
117
+ express = require('express'),
118
+ config = require('./config');
119
119
  ```
120
120
 
121
121
  And install the dependencies as usual with `npm install`. You will have to require both `express` and `http` in your
@@ -129,16 +129,16 @@ function initSouthbound(callback) {
129
129
  southboundServer = {
130
130
  server: null,
131
131
  app: express(),
132
- router: express.Router(),
132
+ router: express.Router()
133
133
  };
134
134
 
135
- southboundServer.app.set("port", 8080);
136
- southboundServer.app.set("host", "0.0.0.0");
135
+ southboundServer.app.set('port', 8080);
136
+ southboundServer.app.set('host', '0.0.0.0');
137
137
 
138
- southboundServer.router.get("/iot/d", manageULRequest);
138
+ southboundServer.router.get('/iot/d', manageULRequest);
139
139
  southboundServer.server = http.createServer(southboundServer.app);
140
- southboundServer.app.use("/", southboundServer.router);
141
- southboundServer.server.listen(southboundServer.app.get("port"), southboundServer.app.get("host"), callback);
140
+ southboundServer.app.use('/', southboundServer.router);
141
+ southboundServer.server.listen(southboundServer.app.get('port'), southboundServer.app.get('host'), callback);
142
142
  }
143
143
  ```
144
144
 
@@ -154,18 +154,18 @@ function manageULRequest(req, res, next) {
154
154
  iotAgentLib.retrieveDevice(req.query.i, req.query.k, function (error, device) {
155
155
  if (error) {
156
156
  res.status(404).send({
157
- message: "Couldn't find the device: " + JSON.stringify(error),
157
+ message: "Couldn't find the device: " + JSON.stringify(error)
158
158
  });
159
159
  } else {
160
160
  values = parseUl(req.query.d, device);
161
- iotAgentLib.update(device.name, device.type, "", values, device, function (error) {
161
+ iotAgentLib.update(device.name, device.type, '', values, device, function (error) {
162
162
  if (error) {
163
163
  res.status(500).send({
164
- message: "Error updating the device",
164
+ message: 'Error updating the device'
165
165
  });
166
166
  } else {
167
167
  res.status(200).send({
168
- message: "Device successfully updated",
168
+ message: 'Device successfully updated'
169
169
  });
170
170
  }
171
171
  });
@@ -190,17 +190,17 @@ function parseUl(data, device) {
190
190
  }
191
191
 
192
192
  function createAttribute(element) {
193
- var pair = element.split("|"),
193
+ var pair = element.split('|'),
194
194
  attribute = {
195
195
  name: pair[0],
196
196
  value: pair[1],
197
- type: findType(pair[0]),
197
+ type: findType(pair[0])
198
198
  };
199
199
 
200
200
  return attribute;
201
201
  }
202
202
 
203
- return data.split(",").map(createAttribute);
203
+ return data.split(',').map(createAttribute);
204
204
  }
205
205
  ```
206
206
 
@@ -227,14 +227,14 @@ show the modifications in the `activate()` function:
227
227
  ```javascript
228
228
  iotAgentLib.activate(config, function (error) {
229
229
  if (error) {
230
- console.log("There was an error activating the IOTA");
230
+ console.log('There was an error activating the IOTA');
231
231
  process.exit(1);
232
232
  } else {
233
233
  initSouthbound(function (error) {
234
234
  if (error) {
235
- console.log("Could not initialize South bound API due to the following error: %s", error);
235
+ console.log('Could not initialize South bound API due to the following error: %s', error);
236
236
  } else {
237
- console.log("Both APIs started successfully");
237
+ console.log('Both APIs started successfully');
238
238
  }
239
239
  });
240
240
  }
@@ -286,7 +286,7 @@ A HTTP request library will be needed in order to make those calls. To this exte
286
286
  used. In order to do so, add the following require statement to the initialization code:
287
287
 
288
288
  ```javascript
289
- request = require("request");
289
+ request = require('request');
290
290
  ```
291
291
 
292
292
  and add the `request` dependency to the `package.json` file:
@@ -303,11 +303,11 @@ and add the `request` dependency to the `package.json` file:
303
303
  The require section should now look like this:
304
304
 
305
305
  ```javascript
306
- var iotAgentLib = require("iotagent-node-lib"),
307
- http = require("http"),
308
- express = require("express"),
309
- request = require("request"),
310
- config = require("./config");
306
+ var iotAgentLib = require('iotagent-node-lib'),
307
+ http = require('http'),
308
+ express = require('express'),
309
+ request = require('request'),
310
+ config = require('./config');
311
311
  ```
312
312
 
313
313
  ### Implementation
@@ -321,11 +321,11 @@ for the context provisioning requests. At this point, we should provide two hand
321
321
  ```javascript
322
322
  function queryContextHandler(id, type, service, subservice, attributes, callback) {
323
323
  var options = {
324
- url: "http://127.0.0.1:9999/iot/d",
325
- method: "GET",
324
+ url: 'http://127.0.0.1:9999/iot/d',
325
+ method: 'GET',
326
326
  qs: {
327
- q: attributes.join(),
328
- },
327
+ q: attributes.join()
328
+ }
329
329
  };
330
330
 
331
331
  request(options, function (error, response, body) {
@@ -350,21 +350,21 @@ attributes). Here is the code for the `createResponse()` function:
350
350
 
351
351
  ```javascript
352
352
  function createResponse(id, type, attributes, body) {
353
- var values = body.split(","),
353
+ var values = body.split(','),
354
354
  responses = [];
355
355
 
356
356
  for (var i = 0; i < attributes.length; i++) {
357
357
  responses.push({
358
358
  name: attributes[i],
359
- type: "string",
360
- value: values[i],
359
+ type: 'string',
360
+ value: values[i]
361
361
  });
362
362
  }
363
363
 
364
364
  return {
365
365
  id: id,
366
366
  type: type,
367
- attributes: responses,
367
+ attributes: responses
368
368
  };
369
369
  }
370
370
  ```
@@ -374,11 +374,11 @@ function createResponse(id, type, attributes, body) {
374
374
  ```javascript
375
375
  function updateContextHandler(id, type, service, subservice, attributes, callback) {
376
376
  var options = {
377
- url: "http://127.0.0.1:9999/iot/d",
378
- method: "GET",
377
+ url: 'http://127.0.0.1:9999/iot/d',
378
+ method: 'GET',
379
379
  qs: {
380
- d: createQueryFromAttributes(attributes),
381
- },
380
+ d: createQueryFromAttributes(attributes)
381
+ }
382
382
  };
383
383
 
384
384
  request(options, function (error, response, body) {
@@ -388,31 +388,31 @@ function updateContextHandler(id, type, service, subservice, attributes, callbac
388
388
  callback(null, {
389
389
  id: id,
390
390
  type: type,
391
- attributes: attributes,
391
+ attributes: attributes
392
392
  });
393
393
  }
394
394
  });
395
395
  }
396
396
  ```
397
397
 
398
- The updateContext handler deals with the modification requests that arrive at the North Port of the IoT Agent via `/v2/op/update`. It is
399
- invoked once for each entity requested (note that a single request can contain multiple entity updates), with the same
400
- parameters used in the queryContext handler. The only difference is the value of the attributes array, now containing a
401
- list of attribute objects, each containing name, type and value. The handler must also make use of the callback to
402
- return a list of updated attributes.
398
+ The updateContext handler deals with the modification requests that arrive at the North Port of the IoT Agent via
399
+ `/v2/op/update`. It is invoked once for each entity requested (note that a single request can contain multiple entity
400
+ updates), with the same parameters used in the queryContext handler. The only difference is the value of the attributes
401
+ array, now containing a list of attribute objects, each containing name, type and value. The handler must also make use
402
+ of the callback to return a list of updated attributes.
403
403
 
404
404
  For this handler we have used a helper function called `createQueryFromAttributes()`, that transforms the NGSI
405
405
  representation of the attributes to the UL type expected by the device:
406
406
 
407
407
  ```javascript
408
408
  function createQueryFromAttributes(attributes) {
409
- var query = "";
409
+ var query = '';
410
410
 
411
411
  for (var i in attributes) {
412
- query += attributes[i].name + "|" + attributes[i].value;
412
+ query += attributes[i].name + '|' + attributes[i].value;
413
413
 
414
414
  if (i != attributes.length - 1) {
415
- query += ",";
415
+ query += ',';
416
416
  }
417
417
  }
418
418
 
@@ -544,10 +544,6 @@ request/seconds that can be manage by the server. It's important to remark that
544
544
  included in the IoT Agent Node Lib but it is not mandatory that you activate this functionality. In this example, we
545
545
  will see how to use this functionality to deploy an IoT Agent in multi-thread environment.
546
546
 
547
- **WARNING:** it has been observed in Orion-IOTA integration tests some fails in bidirectional plugin usage scenarios in
548
- multi-thread mode. The fail has not been confirmed yet (it could be a glitch of the testing environment). However, take
549
- this into account if you use multi-thread in combination with bidirectional plugin.
550
-
551
547
  In order to activate the functionality, you have two options, configure the `config.js` file to add the following line:
552
548
 
553
549
  ```javascript
@@ -563,9 +559,9 @@ variable and afterward the value of the multiCore in the `config.js` file. The r
563
559
  (the standard `http` module is also needed):
564
560
 
565
561
  ```javascript
566
- var iotAgent = require("../lib/iotagent-implementation"),
567
- iotAgentLib = require("iotagent-node-lib"),
568
- config = require("./config");
562
+ var iotAgent = require('../lib/iotagent-implementation'),
563
+ iotAgentLib = require('iotagent-node-lib'),
564
+ config = require('./config');
569
565
  ```
570
566
 
571
567
  It is important to mention the purpose of the `iotAgent` variable. It is the proper implementation of the IoT Agent
@@ -581,9 +577,9 @@ about starting the IoTAgent:
581
577
  ```javascript
582
578
  iotAgentLib.startServer(config, iotAgent, function (error) {
583
579
  if (error) {
584
- console.log(context, "Error starting IoT Agent: [%s] Exiting process", error);
580
+ console.log(context, 'Error starting IoT Agent: [%s] Exiting process', error);
585
581
  } else {
586
- console.log(context, "IoT Agent started");
582
+ console.log(context, 'IoT Agent started');
587
583
  }
588
584
  });
589
585
  ```
@@ -610,7 +606,7 @@ handlers themselves. Here we can see the definition of the configuration handler
610
606
 
611
607
  ```javascript
612
608
  function configurationHandler(configuration, callback) {
613
- console.log("\n\n* REGISTERING A NEW CONFIGURATION:\n%s\n\n", JSON.stringify(configuration, null, 4));
609
+ console.log('\n\n* REGISTERING A NEW CONFIGURATION:\n%s\n\n', JSON.stringify(configuration, null, 4));
614
610
  callback(null, configuration);
615
611
  }
616
612
  ```
@@ -627,8 +623,8 @@ feature, let's use the provisioning handler to change the value of the type of t
627
623
 
628
624
  ```javascript
629
625
  function provisioningHandler(device, callback) {
630
- console.log("\n\n* REGISTERING A NEW DEVICE:\n%s\n\n", JSON.stringify(device, null, 4));
631
- device.type = "CertifiedType";
626
+ console.log('\n\n* REGISTERING A NEW DEVICE:\n%s\n\n', JSON.stringify(device, null, 4));
627
+ device.type = 'CertifiedType';
632
628
  callback(null, device);
633
629
  }
634
630
  ```
@@ -249,10 +249,6 @@ used for the same purpose. For instance:
249
249
  'http://192.168.56.1:4041'.
250
250
  - **iotaVersion**: indicates the version of the IoTA that will be displayed in the about method (it should be filled
251
251
  automatically by each IoTA).
252
- - **appendMode**: if this flag is activated, the update requests to the Context Broker will be performed always with
253
- APPEND type, instead of the default UPDATE. This have implications in the use of attributes with Context Providers,
254
- so this flag should be used with care. This flag is overwritten by `autoprovision` flag in group or device
255
- provision.
256
252
  - **dieOnUnexpectedError**: if this flag is activated, the IoTAgent will not capture global exception, thus dying upon
257
253
  any unexpected error.
258
254
  - **singleConfigurationMode**: enables the Single Configuration mode for backwards compatibility (see description in
@@ -352,7 +348,6 @@ overrides.
352
348
  | IOTA_MONGO_SSL | `mongodb.ssl` |
353
349
  | IOTA_MONGO_EXTRAARGS | `mongodb.extraArgs` |
354
350
  | IOTA_SINGLE_MODE | `singleConfigurationMode` |
355
- | IOTA_APPEND_MODE | `appendMode` |
356
351
  | IOTA_POLLING_EXPIRATION | `pollingExpiration` |
357
352
  | IOTA_POLLING_DAEMON_FREQ | `pollingDaemonFrequency` |
358
353
  | IOTA_AUTOCAST | `autocast` |
@@ -1,4 +1,4 @@
1
1
  mkdocs==1.2.3
2
- Pygments==2.9.0
2
+ Pygments==2.15.0
3
3
  Markdown==3.3.4
4
4
  jinja2==3.0.0
@@ -1,4 +1,4 @@
1
- ARG IMAGE_TAG=11.3-slim
1
+ ARG IMAGE_TAG=12.1-slim
2
2
  FROM debian:${IMAGE_TAG}
3
3
 
4
4
  ARG CLEAN_DEV_TOOLS
@@ -51,7 +51,6 @@ const Device = new Schema({
51
51
  creationDate: { type: Date, default: Date.now },
52
52
  internalAttributes: Object,
53
53
  autoprovision: Boolean,
54
- expressionLanguage: String,
55
54
  explicitAttrs: Group.ExplicitAttrsType,
56
55
  ngsiVersion: String
57
56
  });
@@ -59,7 +59,6 @@ const Group = new Schema({
59
59
  attributes: Array,
60
60
  internalAttributes: Array,
61
61
  autoprovision: Boolean,
62
- expressionLanguage: String,
63
62
  explicitAttrs: ExplicitAttrsType,
64
63
  defaultEntityNameConjunction: String,
65
64
  ngsiVersion: String,
@@ -106,13 +106,7 @@ function init(host, db, port, options, callback) {
106
106
  }
107
107
 
108
108
  function connectionAttempt(url, options, callback) {
109
- logger.info(
110
- context,
111
- 'Attempting to connect to MongoDB instance with url %j and options %j. Attempt %d',
112
- url,
113
- options,
114
- retries
115
- );
109
+ logger.info(context, 'Attempting to connect to MongoDB instance with url %j. Attempt %d', url, retries);
116
110
  // FIXME: useNewUrlParser is no longer used in underlying mongodb driver 4.x
117
111
  // (see https://github.com/mongodb/node-mongodb-native/blob/HEAD/etc/notes/CHANGES_4.0.0.md)
118
112
  // but not sure if current mongoose version is still using mongodb 3.x internally
@@ -77,7 +77,7 @@ function extractVariables(expression) {
77
77
  variables = tokens.filter(function (token, index, array) {
78
78
  return (
79
79
  (token.type === ' ' && array[index - 1].type !== 'dot') ||
80
- (token.type === 'identifier' && array[index + 1].type !== 'openParen')
80
+ (token.type === 'identifier' && array[index + 1] && array[index + 1].type !== 'openParen')
81
81
  );
82
82
  });
83
83
 
@@ -58,7 +58,6 @@ function register(callback) {
58
58
  timestamp: service.timestamp,
59
59
  autoprovision: service.autoprovision,
60
60
  explicitAttrs: service.explicitAttrs,
61
- expressionLanguage: service.expressionLanguage,
62
61
  defaultEntityNameConjunction: service.defaultEntityNameConjunction,
63
62
  ngsiVersion: service.ngsiVersion,
64
63
  entityNameExp: service.entityNameExp
@@ -55,7 +55,6 @@ const attributeList = [
55
55
  'polling',
56
56
  'timestamp',
57
57
  'explicitAttrs',
58
- 'expressionLanguage',
59
58
  'ngsiVersion'
60
59
  ];
61
60
 
@@ -176,15 +175,15 @@ function listDevices(type, service, subservice, limit, offset, callback) {
176
175
  query.skip(parseInt(offset, 10));
177
176
  }
178
177
 
179
- async.series([query.exec.bind(query), Device.model.countDocuments.bind(Device.model, condition)], function (
180
- error,
181
- results
182
- ) {
183
- callback(error, {
184
- count: results[1],
185
- devices: results[0]
186
- });
187
- });
178
+ async.series(
179
+ [query.exec.bind(query), Device.model.countDocuments.bind(Device.model, condition)],
180
+ function (error, results) {
181
+ callback(error, {
182
+ count: results[1],
183
+ devices: results[0]
184
+ });
185
+ }
186
+ );
188
187
  }
189
188
 
190
189
  function findOneInMongoDB(queryParams, id, callback) {
@@ -303,6 +302,7 @@ function update(device, callback) {
303
302
  data.registrationId = device.registrationId;
304
303
  data.explicitAttrs = device.explicitAttrs;
305
304
  data.ngsiVersion = device.ngsiVersion;
305
+ data.timestamp = device.timestamp;
306
306
 
307
307
  /* eslint-disable-next-line new-cap */
308
308
  const deviceObj = new Device.model(data);
@@ -72,7 +72,12 @@ function init() {
72
72
  * @param {Object} newDevice Device object that will be stored in the database.
73
73
  */
74
74
  function createInitialEntity(deviceData, newDevice, callback) {
75
- deviceHandler.createInitialEntity(deviceData, newDevice, callback);
75
+ if (config.getConfig().appendMode === false || config.ngsiVersion() === 'ld' || deviceData.ngsiVersion === 'ld') {
76
+ deviceHandler.createInitialEntity(deviceData, newDevice, callback);
77
+ } else {
78
+ logger.debug(context, 'Skip create initial entity due appendMode is false or ngsiLD.');
79
+ callback(null, newDevice);
80
+ }
76
81
  }
77
82
 
78
83
  /**
@@ -178,13 +183,12 @@ function mergeDeviceWithConfiguration(fields, defaults, deviceData, configuratio
178
183
  if (configuration && configuration.ngsiVersion) {
179
184
  deviceData.ngsiVersion = configuration.ngsiVersion;
180
185
  }
181
- if (configuration && configuration.expressionLanguage && deviceData.expressionLanguage === undefined) {
182
- deviceData.expressionLanguage = configuration.expressionLanguage;
183
- }
184
186
  if (configuration && configuration.explicitAttrs !== undefined && deviceData.explicitAttrs === undefined) {
185
187
  deviceData.explicitAttrs = configuration.explicitAttrs;
186
188
  }
187
-
189
+ if (configuration && configuration.entityNameExp !== undefined) {
190
+ deviceData.entityNameExp = configuration.entityNameExp;
191
+ }
188
192
  logger.debug(context, 'deviceData after merge with conf: %j', deviceData);
189
193
  callback(null, deviceData);
190
194
  }
@@ -265,7 +269,7 @@ function registerDevice(deviceObj, callback) {
265
269
  function prepareDeviceData(deviceObj, configuration, callback) {
266
270
  const deviceData = _.clone(deviceObj);
267
271
  let selectedConfiguration;
268
-
272
+ logger.debug(context, 'Prepare device data:\n%s', JSON.stringify(deviceData, null, 4));
269
273
  if (!deviceData.type) {
270
274
  if (configuration && configuration.type) {
271
275
  deviceData.type = configuration.type;
@@ -362,9 +366,9 @@ function registerDevice(deviceObj, callback) {
362
366
  deviceObj.service = deviceData.service;
363
367
  deviceObj.subservice = deviceData.subservice;
364
368
  deviceObj.type = deviceData.type;
365
- deviceObj.staticAttributes = deviceData.staticAttributes;
366
- deviceObj.commands = deviceData.commands;
367
- deviceObj.lazy = deviceData.lazy;
369
+ deviceObj.staticAttributes = deviceObj.staticAttributes ? deviceObj.staticAttributes : [];
370
+ deviceObj.commands = deviceObj.commands ? deviceObj.commands : [];
371
+ deviceObj.lazy = deviceObj.lazy ? deviceObj.lazy : [];
368
372
  if ('timestamp' in deviceData && deviceData.timestamp !== undefined) {
369
373
  deviceObj.timestamp = deviceData.timestamp;
370
374
  }
@@ -374,6 +378,7 @@ function registerDevice(deviceObj, callback) {
374
378
  if ('apikey' in deviceData && deviceData.apikey !== undefined) {
375
379
  deviceObj.apikey = deviceData.apikey;
376
380
  }
381
+ logger.debug(context, 'Storing device :\n%s', JSON.stringify(deviceObj, null, 4));
377
382
  config.getRegistry().store(deviceObj, callback);
378
383
  }
379
384
  }
@@ -618,19 +623,9 @@ function findOrCreate(deviceId, group, callback) {
618
623
  if (config.getConfig().iotManager && config.getConfig().iotManager.protocol) {
619
624
  newDevice.protocol = config.getConfig().iotManager.protocol;
620
625
  }
621
-
622
- if ('timestamp' in group && group.timestamp !== undefined) {
623
- newDevice.timestamp = group.timestamp;
624
- }
625
626
  if ('ngsiVersion' in group && group.ngsiVersion !== undefined) {
626
627
  newDevice.ngsiVersion = group.ngsiVersion;
627
628
  }
628
- if ('explicitAttrs' in group && group.explicitAttrs !== undefined) {
629
- newDevice.explicitAttrs = group.explicitAttrs;
630
- }
631
- if ('expressionLanguage' in group && group.expressionLanguage !== undefined) {
632
- newDevice.expressionLanguage = group.expressionLanguage;
633
- }
634
629
  if (
635
630
  (!('apikey' in newDevice) || newDevice.apikey === undefined) &&
636
631
  'apikey' in group &&
@@ -240,7 +240,7 @@ function createInitialEntityNgsi2(deviceData, newDevice, callback) {
240
240
  }
241
241
  }
242
242
 
243
- logger.debug(context, 'deviceData: %j', deviceData);
243
+ logger.debug(context, 'Creating initial entity with deviceData: %j', deviceData);
244
244
  if (
245
245
  ('timestamp' in deviceData && deviceData.timestamp !== undefined
246
246
  ? deviceData.timestamp
@@ -356,11 +356,8 @@ function updateRegisterDeviceNgsi2(deviceObj, entityInfoUpdated, callback) {
356
356
  if ('explicitAttrs' in newDevice && newDevice.explicitAttrs !== undefined) {
357
357
  oldDevice.explicitAttrs = newDevice.explicitAttrs;
358
358
  }
359
- if ('expressionLanguage' in newDevice && newDevice.expressionLanguage !== undefined) {
360
- oldDevice.expressionLanguage = newDevice.expressionLanguage;
361
- }
362
359
  if ('apikey' in newDevice && newDevice.apikey !== undefined) {
363
- oldDevice.explicitAttrs = newDevice.apikey;
360
+ oldDevice.apikey = newDevice.apikey;
364
361
  }
365
362
  oldDevice.endpoint = newDevice.endpoint || oldDevice.endpoint;
366
363
 
@@ -439,10 +439,10 @@ function sendUpdateValueNgsiLD(entityName, attributes, typeInformation, token, c
439
439
  payload[0].type = typeInformation.type;
440
440
  }
441
441
 
442
- if (config.getConfig().appendMode === true) {
443
- payload.actionType = 'append';
444
- } else {
442
+ if (config.getConfig().appendMode === false) {
445
443
  payload.actionType = 'update';
444
+ } else {
445
+ payload.actionType = 'append';
446
446
  }
447
447
 
448
448
  const options = NGSIUtils.createRequestObject(url, typeInformation, token);
@@ -354,10 +354,10 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca
354
354
  payload.entities[0].type = typeInformation.type;
355
355
  }
356
356
 
357
- if (config.getConfig().appendMode === true) {
358
- payload.actionType = 'append';
359
- } else {
357
+ if (config.getConfig().appendMode === false) {
360
358
  payload.actionType = 'update';
359
+ } else {
360
+ payload.actionType = 'append';
361
361
  }
362
362
 
363
363
  let options = NGSIUtils.createRequestObject(url, typeInformation, token);
@@ -675,6 +675,23 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca
675
675
  }
676
676
  }
677
677
 
678
+ // Evaluate entityNameExp with a context including measures
679
+ if (typeInformation.entityNameExp !== undefined && typeInformation.entityNameExp !== '') {
680
+ try {
681
+ logger.debug(context, 'sendUpdateValueNgsi2 entityNameExp %j ', typeInformation.entityNameExp);
682
+ entityName = expressionPlugin.applyExpression(typeInformation.entityNameExp, ctxt, typeInformation);
683
+ payload.entities[0].id = entityName;
684
+ ctxt['entity_name'] = entityName;
685
+ } catch (e) {
686
+ logger.debug(
687
+ context,
688
+ 'Error evaluating expression for entityName: %s with context: %s',
689
+ typeInformation.entityNameExp,
690
+ ctxt
691
+ );
692
+ }
693
+ }
694
+
678
695
  logger.debug(context, 'sendUpdateValueNgsi2 currentEntity sorted %j ', currentEntity);
679
696
  let timestampValue = undefined;
680
697
  // Loop for each final attribute to apply alias, multientity and expressions
@@ -970,18 +987,24 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca
970
987
  // only in the first case
971
988
  if (options.json.entities.length === 1) {
972
989
  // recreate options object to use single entity update
973
- url = '/v2/entities/' + entityName + '/attrs';
974
- if (typeInformation && typeInformation.type) {
975
- url += '?type=' + typeInformation.type;
990
+ url = '/v2/entities';
991
+ if (config.getConfig().appendMode === false) {
992
+ url += '/' + entityName + '/attrs';
993
+ if (typeInformation && typeInformation.type) {
994
+ url += '?type=' + typeInformation.type;
995
+ }
996
+ } else {
997
+ // appendMode === true
998
+ url += '?options=upsert';
976
999
  }
977
1000
  options = NGSIUtils.createRequestObject(url, typeInformation, token);
978
1001
  options.json = payload.entities[0];
979
- delete options.json.id;
980
- delete options.json.type;
981
- if (config.getConfig().appendMode === true) {
982
- options.method = 'POST';
983
- } else {
1002
+ if (config.getConfig().appendMode === false) {
984
1003
  options.method = 'PATCH';
1004
+ delete options.json.id;
1005
+ delete options.json.type;
1006
+ } else {
1007
+ options.method = 'POST';
985
1008
  }
986
1009
  } // else: keep current options object created for a batch update
987
1010
  logger.debug(context, 'Updating device value in the Context Broker at [%s]', options.url);
@@ -62,7 +62,6 @@ const provisioningAPITranslation = {
62
62
  static_attributes: 'staticAttributes',
63
63
  autoprovision: 'autoprovision',
64
64
  explicitAttrs: 'explicitAttrs',
65
- expressionLanguage: 'expressionLanguage',
66
65
  ngsiVersion: 'ngsiVersion',
67
66
  entityNameExp: 'entityNameExp'
68
67
  };
@@ -142,7 +141,6 @@ function handleProvision(req, res, next) {
142
141
  internalId: null,
143
142
  autoprovision: body.autoprovision,
144
143
  explicitAttrs: body.explicitAttrs,
145
- expressionLanguage: body.expressionLanguage,
146
144
  ngsiVersion: body.ngsiVersion
147
145
  });
148
146
  }
@@ -219,7 +217,6 @@ function toProvisioningAPIFormat(device) {
219
217
  internal_attributes: device.internalAttributes,
220
218
  protocol: device.protocol,
221
219
  autoprovision: device.autoprovision,
222
- expressionLanguage: device.expressionLanguage,
223
220
  explicitAttrs: device.explicitAttrs,
224
221
  ngsiVersion: device.ngsiVersion
225
222
  };
@@ -36,10 +36,6 @@
36
36
  "description": "Transport protocol used by the platform to communicate with the device",
37
37
  "type": "string"
38
38
  },
39
- "expressionLanguage": {
40
- "description": "Expression language used to apply expressions for this device",
41
- "type": "string"
42
- },
43
39
  "explicitAttrs": {
44
40
  "description": "Flag about only provisioned attributes will be processed to Context Broker"
45
41
  },
@@ -36,10 +36,6 @@
36
36
  "description": "Transport protocol used by the platform to communicate with the device",
37
37
  "type": "string"
38
38
  },
39
- "expressionLanguage": {
40
- "description": "Expression language used to apply expressions for this device",
41
- "type": "string"
42
- },
43
39
  "explicitAttrs": {
44
40
  "description": "Flag about only provisioned attributes will be processed to Context Broker"
45
41
  },