iotagent-node-lib 3.2.0 → 3.4.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 (184) 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/README.md +10 -11
  7. package/doc/README.md +16 -0
  8. package/doc/admin.md +565 -0
  9. package/doc/api.md +32 -85
  10. package/doc/deprecated.md +16 -10
  11. package/doc/{architecture.md → devel/architecture.md} +3 -3
  12. package/doc/{Contribution.md → devel/contribution-guidelines.md} +43 -35
  13. package/doc/devel/development.md +1879 -0
  14. package/doc/{northboundinteractions.md → devel/northboundinteractions.md} +18 -33
  15. package/doc/index.md +3 -5
  16. package/doc/requirements.txt +1 -1
  17. package/docker/Mosquitto/Dockerfile +1 -1
  18. package/docker/Mosquitto/README.md +1 -0
  19. package/lib/commonConfig.js +0 -5
  20. package/lib/fiware-iotagent-lib.js +1 -1
  21. package/lib/jexlTranformsMap.js +2 -1
  22. package/lib/model/Device.js +0 -1
  23. package/lib/model/Group.js +0 -1
  24. package/lib/model/dbConn.js +1 -7
  25. package/lib/plugins/jexlParser.js +1 -1
  26. package/lib/request-shim.js +2 -2
  27. package/lib/services/commands/commandService.js +1 -1
  28. package/lib/services/common/genericMiddleware.js +1 -1
  29. package/lib/services/common/iotManagerService.js +0 -1
  30. package/lib/services/devices/deviceRegistryMemory.js +2 -2
  31. package/lib/services/devices/deviceRegistryMongoDB.js +32 -19
  32. package/lib/services/devices/deviceService.js +44 -43
  33. package/lib/services/devices/devices-NGSI-LD.js +14 -2
  34. package/lib/services/devices/devices-NGSI-mixed.js +0 -2
  35. package/lib/services/devices/devices-NGSI-v2.js +23 -104
  36. package/lib/services/groups/groupService.js +1 -1
  37. package/lib/services/ngsi/entities-NGSI-LD.js +3 -3
  38. package/lib/services/ngsi/entities-NGSI-v2.js +28 -19
  39. package/lib/services/northBound/deviceProvisioningServer.js +14 -8
  40. package/lib/templates/createDevice.json +0 -4
  41. package/lib/templates/createDeviceLax.json +0 -4
  42. package/lib/templates/deviceGroup.json +1 -5
  43. package/lib/templates/updateDevice.json +4 -0
  44. package/lib/templates/updateDeviceLax.json +11 -0
  45. package/mkdocs.yml +6 -11
  46. package/package.json +3 -3
  47. package/scripts/legacy_expression_tool/README.md +280 -0
  48. package/scripts/legacy_expression_tool/legacy_expression_tool.py +423 -0
  49. package/scripts/legacy_expression_tool/requirements.txt +3 -0
  50. package/test/unit/examples/deviceProvisioningRequests/provisionMinimumDevice4.json +0 -1
  51. package/test/unit/general/contextBrokerKeystoneSecurityAccess-test.js +5 -15
  52. package/test/unit/mongodb/mongodb-registry-test.js +1 -1
  53. package/test/unit/ngsi-ld/general/contextBrokerOAuthSecurityAccess-test.js +66 -65
  54. package/test/unit/ngsi-ld/general/https-support-test.js +1 -1
  55. package/test/unit/ngsi-ld/lazyAndCommands/command-test.js +8 -7
  56. package/test/unit/ngsi-ld/lazyAndCommands/merge-patch-test.js +31 -30
  57. package/test/unit/ngsi-ld/lazyAndCommands/polling-commands-test.js +12 -11
  58. package/test/unit/ngsi-ld/ngsiService/subscriptions-test.js +41 -39
  59. package/test/unit/ngsi-ld/provisioning/device-provisioning-api_test.js +122 -122
  60. package/test/unit/ngsi-ld/provisioning/device-registration_test.js +28 -28
  61. package/test/unit/ngsi-ld/provisioning/device-update-registration_test.js +18 -17
  62. package/test/unit/ngsi-ld/provisioning/singleConfigurationMode-test.js +7 -7
  63. package/test/unit/ngsi-ld/provisioning/updateProvisionedDevices-test.js +8 -7
  64. package/test/unit/ngsi-mixed/provisioning/ngsi-versioning-test.js +33 -37
  65. package/test/unit/ngsiv2/examples/contextRequests/updateContext.json +2 -0
  66. package/test/unit/ngsiv2/examples/contextRequests/updateContext1.json +3 -1
  67. package/test/unit/ngsiv2/examples/contextRequests/updateContext3WithStatic.json +2 -0
  68. package/test/unit/ngsiv2/examples/contextRequests/updateContext4.json +4 -1
  69. package/test/unit/ngsiv2/examples/contextRequests/updateContext5.json +12 -0
  70. package/test/unit/ngsiv2/examples/contextRequests/updateContext6.json +12 -0
  71. package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin1.json +2 -0
  72. package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin2.json +3 -1
  73. package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin3.json +3 -1
  74. package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin4.json +3 -1
  75. package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin5.json +3 -1
  76. package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin6.json +3 -1
  77. package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin7.json +3 -1
  78. package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin8.json +3 -1
  79. package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin9.json +3 -1
  80. package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast1.json +2 -0
  81. package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast2.json +2 -0
  82. package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast3.json +3 -1
  83. package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast4.json +3 -1
  84. package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast5.json +3 -1
  85. package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast6.json +3 -1
  86. package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast7.json +3 -1
  87. package/test/unit/ngsiv2/examples/contextRequests/updateContextCommandError.json +3 -1
  88. package/test/unit/ngsiv2/examples/contextRequests/updateContextCommandExpired.json +3 -1
  89. package/test/unit/ngsiv2/examples/contextRequests/updateContextCommandFinish.json +3 -1
  90. package/test/unit/ngsiv2/examples/contextRequests/updateContextCommandStatus.json +2 -0
  91. package/test/unit/ngsiv2/examples/contextRequests/updateContextCommandStatus2.json +2 -0
  92. package/test/unit/ngsiv2/examples/contextRequests/updateContextCompressTimestamp1.json +3 -1
  93. package/test/unit/ngsiv2/examples/contextRequests/updateContextCompressTimestamp2.json +3 -1
  94. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin1.json +2 -12
  95. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin11.json +2 -4
  96. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin12.json +2 -4
  97. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin13.json +3 -1
  98. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin2.json +2 -12
  99. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin29.json +2 -12
  100. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin3.json +2 -4
  101. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin30.json +2 -0
  102. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin31.json +2 -0
  103. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin32.json +2 -0
  104. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin33.json +2 -0
  105. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin34.json +2 -0
  106. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin35.json +2 -0
  107. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin36.json +1 -0
  108. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin4.json +2 -0
  109. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin40.json +1 -1
  110. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin41.json +1 -10
  111. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin5.json +2 -4
  112. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin6.json +2 -4
  113. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin7.json +2 -4
  114. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin8.json +2 -12
  115. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin9.json +2 -4
  116. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionSkip.json +12 -0
  117. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityJexlExpressionPlugin1.json +1 -1
  118. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin1.json +1 -1
  119. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin10.json +1 -1
  120. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin11.json +1 -1
  121. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin12.json +1 -1
  122. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin13.json +1 -1
  123. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin14.json +1 -1
  124. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin15.json +1 -1
  125. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin16.json +1 -1
  126. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin17.json +1 -1
  127. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin2.json +1 -1
  128. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin25.json +2 -6
  129. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin3.json +1 -1
  130. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin4.json +1 -1
  131. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin5.json +1 -1
  132. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin6.json +1 -1
  133. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin7.json +1 -1
  134. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin8.json +1 -1
  135. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin9.json +1 -1
  136. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin1.json +1 -1
  137. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin2.json +1 -1
  138. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin3.json +1 -1
  139. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin4.json +2 -0
  140. package/test/unit/ngsiv2/examples/contextRequests/updateContextProcessTimestamp.json +2 -0
  141. package/test/unit/ngsiv2/examples/contextRequests/updateContextStaticAttributes.json +2 -0
  142. package/test/unit/ngsiv2/examples/contextRequests/updateContextStaticAttributesMetadata.json +3 -1
  143. package/test/unit/ngsiv2/examples/contextRequests/updateContextTimestamp.json +3 -1
  144. package/test/unit/ngsiv2/examples/contextRequests/updateContextTimestampFalse.json +12 -0
  145. package/test/unit/ngsiv2/examples/contextRequests/updateContextTimestampFalseTimeInstant.json +12 -0
  146. package/test/unit/ngsiv2/examples/contextRequests/updateContextTimestampOverride.json +2 -0
  147. package/test/unit/ngsiv2/examples/contextRequests/updateContextTimestampOverrideWithoutMilis.json +2 -0
  148. package/test/unit/ngsiv2/examples/contextRequests/updateContextTimestampTimezone.json +3 -1
  149. package/test/unit/ngsiv2/expressions/jexlBasedTransformations-test.js +144 -85
  150. package/test/unit/ngsiv2/general/contextBrokerOAuthSecurityAccess-test.js +20 -53
  151. package/test/unit/ngsiv2/general/https-support-test.js +2 -6
  152. package/test/unit/ngsiv2/lazyAndCommands/command-test.js +4 -10
  153. package/test/unit/ngsiv2/lazyAndCommands/polling-commands-test.js +8 -24
  154. package/test/unit/ngsiv2/ngsiService/active-devices-test.js +146 -65
  155. package/test/unit/ngsiv2/ngsiService/autocast-test.js +14 -21
  156. package/test/unit/ngsiv2/ngsiService/staticAttributes-test.js +3 -5
  157. package/test/unit/ngsiv2/ngsiService/subscriptions-test.js +11 -20
  158. package/test/unit/ngsiv2/plugins/alias-plugin_test.js +20 -30
  159. package/test/unit/ngsiv2/plugins/compress-timestamp-plugin_test.js +4 -6
  160. package/test/unit/ngsiv2/plugins/custom-plugin_test.js +1 -2
  161. package/test/unit/ngsiv2/plugins/multientity-plugin_test.js +3 -5
  162. package/test/unit/ngsiv2/plugins/timestamp-processing-plugin_test.js +2 -3
  163. package/test/unit/ngsiv2/provisioning/device-group-api-test.js +2 -3
  164. package/test/unit/ngsiv2/provisioning/device-provisioning-api_test.js +13 -156
  165. package/test/unit/ngsiv2/provisioning/device-registration_test.js +9 -13
  166. package/test/unit/ngsiv2/provisioning/device-update-registration_test.js +4 -10
  167. package/test/unit/ngsiv2/provisioning/singleConfigurationMode-test.js +0 -11
  168. package/test/unit/ngsiv2/provisioning/updateProvisionedDevices-test.js +0 -8
  169. package/test/unit/plugins/capture-provision-inPlugins_test.js +0 -6
  170. package/.nyc_output/33364de2-1199-4ec2-b33c-cae063ef8cc4.json +0 -1
  171. package/.nyc_output/processinfo/33364de2-1199-4ec2-b33c-cae063ef8cc4.json +0 -1
  172. package/.nyc_output/processinfo/index.json +0 -1
  173. package/doc/config-basic-example.js +0 -20
  174. package/doc/development.md +0 -285
  175. package/doc/howto.md +0 -645
  176. package/doc/installationguide.md +0 -370
  177. package/doc/operations.md +0 -127
  178. package/doc/usermanual.md +0 -900
  179. package/lib/plugins/bidirectionalData.js +0 -356
  180. package/test/unit/ngsi-ld/plugins/bidirectional-plugin_test.js +0 -697
  181. package/test/unit/ngsiv2/plugins/bidirectional-plugin_test.js +0 -599
  182. /package/doc/{NorthboundInteractions.postman_collection → devel/NorthboundInteractions.postman_collection} +0 -0
  183. /package/doc/{echo.js → devel/echo.js} +0 -0
  184. /package/doc/{finalResult.js → devel/finalResult.js} +0 -0
@@ -64,17 +64,6 @@ function init() {
64
64
  }
65
65
  }
66
66
 
67
- /**
68
- * Creates the initial entity representing the device in the Context Broker. This is important mainly to allow the
69
- * rest of the updateContext operations to be performed using an UPDATE action instead of an APPEND one.
70
- *
71
- * @param {Object} deviceData Object containing all the deviceData needed to send the registration.
72
- * @param {Object} newDevice Device object that will be stored in the database.
73
- */
74
- function createInitialEntity(deviceData, newDevice, callback) {
75
- deviceHandler.createInitialEntity(deviceData, newDevice, callback);
76
- }
77
-
78
67
  /**
79
68
  * If the object_id or the name of the attribute is missing, complete it with the other piece of data.
80
69
  *
@@ -178,13 +167,12 @@ function mergeDeviceWithConfiguration(fields, defaults, deviceData, configuratio
178
167
  if (configuration && configuration.ngsiVersion) {
179
168
  deviceData.ngsiVersion = configuration.ngsiVersion;
180
169
  }
181
- if (configuration && configuration.expressionLanguage && deviceData.expressionLanguage === undefined) {
182
- deviceData.expressionLanguage = configuration.expressionLanguage;
183
- }
184
170
  if (configuration && configuration.explicitAttrs !== undefined && deviceData.explicitAttrs === undefined) {
185
171
  deviceData.explicitAttrs = configuration.explicitAttrs;
186
172
  }
187
-
173
+ if (configuration && configuration.entityNameExp !== undefined) {
174
+ deviceData.entityNameExp = configuration.entityNameExp;
175
+ }
188
176
  logger.debug(context, 'deviceData after merge with conf: %j', deviceData);
189
177
  callback(null, deviceData);
190
178
  }
@@ -249,6 +237,7 @@ function registerDevice(deviceObj, callback) {
249
237
  function checkDuplicates(deviceObj, innerCb) {
250
238
  config.getRegistry().getSilently(
251
239
  deviceObj.id,
240
+ deviceObj.apikey,
252
241
  deviceObj.service,
253
242
  deviceObj.subservice,
254
243
  /* eslint-disable-next-line no-unused-vars */
@@ -265,7 +254,7 @@ function registerDevice(deviceObj, callback) {
265
254
  function prepareDeviceData(deviceObj, configuration, callback) {
266
255
  const deviceData = _.clone(deviceObj);
267
256
  let selectedConfiguration;
268
-
257
+ logger.debug(context, 'Prepare device data:\n%s', JSON.stringify(deviceData, null, 4));
269
258
  if (!deviceData.type) {
270
259
  if (configuration && configuration.type) {
271
260
  deviceData.type = configuration.type;
@@ -350,8 +339,7 @@ function registerDevice(deviceObj, callback) {
350
339
  async.waterfall(
351
340
  [
352
341
  apply(registrationUtils.sendRegistrations, false, deviceData),
353
- apply(registrationUtils.processContextRegistration, deviceData),
354
- apply(createInitialEntity, deviceData)
342
+ apply(registrationUtils.processContextRegistration, deviceData)
355
343
  ],
356
344
  function (error, results) {
357
345
  if (error) {
@@ -362,9 +350,9 @@ function registerDevice(deviceObj, callback) {
362
350
  deviceObj.service = deviceData.service;
363
351
  deviceObj.subservice = deviceData.subservice;
364
352
  deviceObj.type = deviceData.type;
365
- deviceObj.staticAttributes = deviceData.staticAttributes;
366
- deviceObj.commands = deviceData.commands;
367
- deviceObj.lazy = deviceData.lazy;
353
+ deviceObj.staticAttributes = deviceObj.staticAttributes ? deviceObj.staticAttributes : [];
354
+ deviceObj.commands = deviceObj.commands ? deviceObj.commands : [];
355
+ deviceObj.lazy = deviceObj.lazy ? deviceObj.lazy : [];
368
356
  if ('timestamp' in deviceData && deviceData.timestamp !== undefined) {
369
357
  deviceObj.timestamp = deviceData.timestamp;
370
358
  }
@@ -374,6 +362,7 @@ function registerDevice(deviceObj, callback) {
374
362
  if ('apikey' in deviceData && deviceData.apikey !== undefined) {
375
363
  deviceObj.apikey = deviceData.apikey;
376
364
  }
365
+ logger.debug(context, 'Storing device :\n%s', JSON.stringify(deviceObj, null, 4));
377
366
  config.getRegistry().store(deviceObj, callback);
378
367
  }
379
368
  }
@@ -414,7 +403,7 @@ function removeAllSubscriptions(device, callback) {
414
403
  * @param {String} service Service of the device to unregister.
415
404
  * @param {String} subservice Subservice inside the service for the unregisterd device.
416
405
  */
417
- function unregisterDevice(id, service, subservice, callback) {
406
+ function unregisterDevice(id, apikey, service, subservice, callback) {
418
407
  function processContextUnregister(body, innerCallback) {
419
408
  innerCallback(null);
420
409
  }
@@ -423,9 +412,9 @@ function unregisterDevice(id, service, subservice, callback) {
423
412
  innerCallback(null);
424
413
  }
425
414
 
426
- logger.debug(context, 'Removing device register in Device Service');
415
+ logger.debug(context, 'Removing device %j %j %j %j register in Device Service', id, apikey, service, subservice);
427
416
 
428
- config.getRegistry().get(id, service, subservice, function (error, device) {
417
+ config.getRegistry().get(id, apikey, service, subservice, function (error, device) {
429
418
  if (error) {
430
419
  callback(error);
431
420
  } else {
@@ -449,7 +438,7 @@ function unregisterDevice(id, service, subservice, callback) {
449
438
  processUnsubscribes,
450
439
  apply(registrationUtils.sendRegistrations, true, mergedDevice),
451
440
  processContextUnregister,
452
- apply(config.getRegistry().remove, id, service, subservice)
441
+ apply(config.getRegistry().remove, id, apikey, service, subservice)
453
442
  ],
454
443
  callback
455
444
  );
@@ -524,8 +513,17 @@ function listDevices(service, subservice, limit, offset, callback) {
524
513
  * @param {String} service Service for which the requested device.
525
514
  * @param {String} subservice Subservice inside the service for which the device is requested.
526
515
  */
527
- function getDevice(deviceId, service, subservice, callback) {
528
- config.getRegistry().get(deviceId, service, subservice, callback);
516
+ function getDevice(deviceId, apikey, service, subservice, callback) {
517
+ config.getRegistry().get(deviceId, apikey, service, subservice, callback);
518
+ }
519
+
520
+ /**
521
+ * Update a device from the device registry.
522
+ *
523
+ * @param {String} device JSON object contain the device to update.
524
+ */
525
+ function updateDevice(device, callback) {
526
+ config.getRegistry().update(device, callback);
529
527
  }
530
528
 
531
529
  /**
@@ -535,8 +533,8 @@ function getDevice(deviceId, service, subservice, callback) {
535
533
  * @param {String} service Service for which the requested device.
536
534
  * @param {String} subservice Subservice inside the service for which the device is requested.
537
535
  */
538
- function getDeviceSilently(deviceId, service, subservice, callback) {
539
- config.getRegistry().getSilently(deviceId, service, subservice, callback);
536
+ function getDeviceSilently(deviceId, apikey, service, subservice, callback) {
537
+ config.getRegistry().getSilently(deviceId, apikey, service, subservice, callback);
540
538
  }
541
539
 
542
540
  /**
@@ -603,10 +601,22 @@ function checkRegistry(fn) {
603
601
  };
604
602
  }
605
603
 
606
- function findOrCreate(deviceId, group, callback) {
607
- getDeviceSilently(deviceId, group.service, group.subservice, function (error, device) {
604
+ function findOrCreate(deviceId, apikey, group, callback) {
605
+ getDeviceSilently(deviceId, apikey, group.service, group.subservice, function (error, device) {
608
606
  if (!error && device) {
609
- callback(null, device, group);
607
+ if (
608
+ (!('apikey' in device) || device.apikey === undefined) &&
609
+ 'apikey' in group &&
610
+ group.apikey !== undefined
611
+ ) {
612
+ logger.info(context, 'Update provisioned device %j with measure/group apikey %j', device, group.apikey);
613
+ device.apikey = group.apikey; // group apikey is the same of current measure apikey
614
+ updateDevice(device, function (error) {
615
+ callback(error, device, group);
616
+ });
617
+ } else {
618
+ callback(null, device, group);
619
+ }
610
620
  } else if (error.name === 'DEVICE_NOT_FOUND') {
611
621
  const newDevice = {
612
622
  id: deviceId,
@@ -618,19 +628,9 @@ function findOrCreate(deviceId, group, callback) {
618
628
  if (config.getConfig().iotManager && config.getConfig().iotManager.protocol) {
619
629
  newDevice.protocol = config.getConfig().iotManager.protocol;
620
630
  }
621
-
622
- if ('timestamp' in group && group.timestamp !== undefined) {
623
- newDevice.timestamp = group.timestamp;
624
- }
625
631
  if ('ngsiVersion' in group && group.ngsiVersion !== undefined) {
626
632
  newDevice.ngsiVersion = group.ngsiVersion;
627
633
  }
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
634
  if (
635
635
  (!('apikey' in newDevice) || newDevice.apikey === undefined) &&
636
636
  'apikey' in group &&
@@ -683,7 +683,7 @@ function retrieveDevice(deviceId, apiKey, callback) {
683
683
  async.waterfall(
684
684
  [
685
685
  apply(groupService.get, config.getConfig().defaultResource || '', apiKey),
686
- apply(findOrCreate, deviceId),
686
+ apply(findOrCreate, deviceId, apiKey),
687
687
  apply(
688
688
  mergeDeviceWithConfiguration,
689
689
  ['lazy', 'active', 'staticAttributes', 'commands', 'subscriptions'],
@@ -698,6 +698,7 @@ function retrieveDevice(deviceId, apiKey, callback) {
698
698
  exports.listDevices = intoTrans(context, checkRegistry)(listDevices);
699
699
  exports.listDevicesWithType = intoTrans(context, checkRegistry)(listDevicesWithType);
700
700
  exports.getDevice = intoTrans(context, checkRegistry)(getDevice);
701
+ exports.updateDevice = intoTrans(context, checkRegistry)(updateDevice);
701
702
  exports.getDeviceSilently = intoTrans(context, checkRegistry)(getDeviceSilently);
702
703
  exports.getDevicesByAttribute = intoTrans(context, checkRegistry)(getDevicesByAttribute);
703
704
  exports.getDeviceByName = intoTrans(context, checkRegistry)(getDeviceByName);
@@ -369,7 +369,13 @@ function updateRegisterDeviceNgsiLD(deviceObj, entityInfoUpdated, callback) {
369
369
  if (entityInfoUpdated) {
370
370
  async.waterfall(
371
371
  [
372
- apply(config.getRegistry().get, deviceObj.id, deviceObj.service, deviceObj.subservice),
372
+ apply(
373
+ config.getRegistry().get,
374
+ deviceObj.id,
375
+ deviceObj.apikey,
376
+ deviceObj.service,
377
+ deviceObj.subservice
378
+ ),
373
379
  apply(extractDeviceDifference, deviceObj),
374
380
  createInitialEntityNgsiLD,
375
381
  apply(combineWithNewDevice, deviceObj),
@@ -382,7 +388,13 @@ function updateRegisterDeviceNgsiLD(deviceObj, entityInfoUpdated, callback) {
382
388
  } else {
383
389
  async.waterfall(
384
390
  [
385
- apply(config.getRegistry().get, deviceObj.id, deviceObj.service, deviceObj.subservice),
391
+ apply(
392
+ config.getRegistry().get,
393
+ deviceObj.id,
394
+ deviceObj.apikey,
395
+ deviceObj.service,
396
+ deviceObj.subservice
397
+ ),
386
398
  apply(extractDeviceDifference, deviceObj),
387
399
  updateEntityNgsiLD,
388
400
  apply(combineWithNewDevice, deviceObj),
@@ -37,8 +37,6 @@ const deviceHandlerV2 = require('./devices-NGSI-v2');
37
37
  function createInitialEntityNgsiMixed(deviceData, newDevice, callback) {
38
38
  if (config.checkNgsiLD(deviceData)) {
39
39
  deviceHandlerLD.createInitialEntity(deviceData, newDevice, callback);
40
- } else {
41
- deviceHandlerV2.createInitialEntity(deviceData, newDevice, callback);
42
40
  }
43
41
  }
44
42
 
@@ -61,46 +61,6 @@ function jsonConcat(json1, json2) {
61
61
  }
62
62
  }
63
63
 
64
- /**
65
- * Creates the response handler for the initial entity creation request using NGSIv2.
66
- * This handler basically deals with the errors that could have been rised during
67
- * the communication with the Context Broker.
68
- *
69
- * @param {Object} deviceData Object containing all the deviceData needed to send the registration.
70
- * @param {Object} newDevice Device object that will be stored in the database.
71
- * @return {function} Handler to pass to the request() function.
72
- */
73
- function createInitialEntityHandlerNgsi2(deviceData, newDevice, callback) {
74
- return function handleInitialEntityResponse(error, response, body) {
75
- if (error) {
76
- logger.error(
77
- context,
78
- 'ORION-001: Connection error creating inital entity in the Context Broker: %s',
79
- error
80
- );
81
-
82
- alarms.raise(constants.ORION_ALARM, error);
83
-
84
- callback(error);
85
- } else if (response && response.statusCode === 204) {
86
- alarms.release(constants.ORION_ALARM);
87
- logger.debug(context, 'Initial entity created successfully.');
88
- callback(null, newDevice);
89
- } else {
90
- logger.error(
91
- context,
92
- 'Protocol error connecting to the Context Broker [%d]: %s',
93
- response.statusCode,
94
- body
95
- );
96
-
97
- const errorObj = new errors.EntityGenericError(deviceData.id, deviceData.type, body, response.statusCode);
98
-
99
- callback(errorObj);
100
- }
101
- };
102
- }
103
-
104
64
  /**
105
65
  * Creates the response handler for the update entity request using NGSIv2. This handler basically deals with the errors
106
66
  * that could have been rised during the communication with the Context Broker.
@@ -199,62 +159,12 @@ function formatCommandsNgsi2(originalVector) {
199
159
  return attributeList;
200
160
  }
201
161
 
202
- /**
203
- * Creates the initial entity representing the device in the Context Broker using NGSIv2.
204
- * This is important mainly to allow the rest of the updateContext operations to be performed.
205
- *
206
- * @param {Object} deviceData Object containing all the deviceData needed to send the registration.
207
- * @param {Object} newDevice Device object that will be stored in the database.
162
+ /*
163
+ * This methods makes a bypass in updateRegisterDeviceNgsi2 to allow not change
164
+ * extractDeviceDifference and combineWithNewDevice methods
208
165
  */
209
- function createInitialEntityNgsi2(deviceData, newDevice, callback) {
210
- const options = {
211
- url: config.getConfig().contextBroker.url + '/v2/entities?options=upsert',
212
- method: 'POST',
213
- json: {
214
- id: String(deviceData.name),
215
- type: deviceData.type
216
- },
217
- headers: {
218
- 'fiware-service': deviceData.service,
219
- 'fiware-servicepath': deviceData.subservice,
220
- 'fiware-correlator': (domain.active && domain.active.corr) || uuid.v4()
221
- }
222
- };
223
-
224
- if (deviceData.cbHost && deviceData.cbHost.indexOf('://') !== -1) {
225
- options.url = deviceData.cbHost + '/v2/entities?options=upsert';
226
- } else if (deviceData.cbHost && deviceData.cbHost.indexOf('://') === -1) {
227
- options.url = 'http://' + deviceData.cbHost + '/v2/entities?options=upsert';
228
- }
229
-
230
- jsonConcat(options.json, formatAttributesNgsi2(deviceData.active, false));
231
- jsonConcat(options.json, formatAttributesNgsi2(deviceData.staticAttributes, true));
232
- jsonConcat(options.json, formatCommandsNgsi2(deviceData.commands));
233
-
234
- for (const att in options.json) {
235
- try {
236
- // Format any GeoJSON attrs properly
237
- options.json[att] = NGSIv2.formatGeoAttrs(options.json[att]);
238
- } catch (error) {
239
- return callback(new errors.BadGeocoordinates(JSON.stringify(options.json)));
240
- }
241
- }
242
-
243
- logger.debug(context, 'deviceData: %j', deviceData);
244
- if (
245
- ('timestamp' in deviceData && deviceData.timestamp !== undefined
246
- ? deviceData.timestamp
247
- : config.getConfig().timestamp) &&
248
- !utils.isTimestampedNgsi2(options.json)
249
- ) {
250
- logger.debug(context, 'config.timestamp %s %s', deviceData.timestamp, config.getConfig().timestamp);
251
- options.json[constants.TIMESTAMP_ATTRIBUTE] = {
252
- type: constants.TIMESTAMP_TYPE_NGSI2,
253
- value: moment()
254
- };
255
- }
256
- logger.debug(context, 'Creating initial entity in the Context Broker:\n %s', JSON.stringify(options, null, 4));
257
- utils.executeWithSecurity(options, newDevice, createInitialEntityHandlerNgsi2(deviceData, newDevice, callback));
166
+ function createInitialEntityNgsi2Fake(deviceData, newDevice, callback) {
167
+ callback(null, newDevice);
258
168
  }
259
169
 
260
170
  /**
@@ -337,9 +247,10 @@ function updateRegisterDeviceNgsi2(deviceObj, entityInfoUpdated, callback) {
337
247
  return;
338
248
  }
339
249
 
340
- logger.debug(context, 'Update provisioned v2 device in Device Service');
250
+ logger.debug(context, 'Update provisioned v2 device in Device Service %j %j', deviceObj, entityInfoUpdated);
341
251
 
342
252
  function combineWithNewDevice(newDevice, oldDevice, callback) {
253
+ logger.debug(context, 'combineWithNewDevice %j %j', newDevice, oldDevice);
343
254
  if (oldDevice) {
344
255
  oldDevice.internalId = newDevice.internalId;
345
256
  oldDevice.lazy = newDevice.lazy;
@@ -356,11 +267,8 @@ function updateRegisterDeviceNgsi2(deviceObj, entityInfoUpdated, callback) {
356
267
  if ('explicitAttrs' in newDevice && newDevice.explicitAttrs !== undefined) {
357
268
  oldDevice.explicitAttrs = newDevice.explicitAttrs;
358
269
  }
359
- if ('expressionLanguage' in newDevice && newDevice.expressionLanguage !== undefined) {
360
- oldDevice.expressionLanguage = newDevice.expressionLanguage;
361
- }
362
270
  if ('apikey' in newDevice && newDevice.apikey !== undefined) {
363
- oldDevice.explicitAttrs = newDevice.apikey;
271
+ oldDevice.apikey = newDevice.apikey;
364
272
  }
365
273
  oldDevice.endpoint = newDevice.endpoint || oldDevice.endpoint;
366
274
 
@@ -427,9 +335,15 @@ function updateRegisterDeviceNgsi2(deviceObj, entityInfoUpdated, callback) {
427
335
  if (entityInfoUpdated) {
428
336
  async.waterfall(
429
337
  [
430
- apply(config.getRegistry().get, deviceObj.id, deviceObj.service, deviceObj.subservice),
338
+ apply(
339
+ config.getRegistry().get,
340
+ deviceObj.id,
341
+ deviceObj.apikey,
342
+ deviceObj.service,
343
+ deviceObj.subservice
344
+ ),
431
345
  apply(extractDeviceDifference, deviceObj),
432
- createInitialEntityNgsi2,
346
+ createInitialEntityNgsi2Fake,
433
347
  apply(combineWithNewDevice, deviceObj),
434
348
  apply(registrationUtils.sendRegistrations, false),
435
349
  apply(registrationUtils.processContextRegistration, deviceObj),
@@ -440,7 +354,13 @@ function updateRegisterDeviceNgsi2(deviceObj, entityInfoUpdated, callback) {
440
354
  } else {
441
355
  async.waterfall(
442
356
  [
443
- apply(config.getRegistry().get, deviceObj.id, deviceObj.service, deviceObj.subservice),
357
+ apply(
358
+ config.getRegistry().get,
359
+ deviceObj.id,
360
+ deviceObj.apikey,
361
+ deviceObj.service,
362
+ deviceObj.subservice
363
+ ),
444
364
  apply(extractDeviceDifference, deviceObj),
445
365
  updateEntityNgsi2,
446
366
  apply(combineWithNewDevice, deviceObj),
@@ -453,7 +373,6 @@ function updateRegisterDeviceNgsi2(deviceObj, entityInfoUpdated, callback) {
453
373
  }
454
374
  }
455
375
 
456
- exports.createInitialEntity = createInitialEntityNgsi2;
457
376
  exports.updateRegisterDevice = updateRegisterDeviceNgsi2;
458
377
  exports.formatCommands = formatCommandsNgsi2;
459
378
  exports.formatAttributes = formatAttributesNgsi2;
@@ -172,7 +172,7 @@ function remove(service, subservice, resource, apikey, device, callback) {
172
172
  }
173
173
 
174
174
  function unregisterDevice(device, cb) {
175
- deviceService.unregister(device.id, service, subservice, function (error) {
175
+ deviceService.unregister(device.id, device.apikey, service, subservice, function (error) {
176
176
  if (error) {
177
177
  cb(error);
178
178
  }
@@ -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,11 +354,7 @@ 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 {
360
- payload.actionType = 'update';
361
- }
357
+ payload.actionType = 'append';
362
358
 
363
359
  let options = NGSIUtils.createRequestObject(url, typeInformation, token);
364
360
 
@@ -675,6 +671,23 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca
675
671
  }
676
672
  }
677
673
 
674
+ // Evaluate entityNameExp with a context including measures
675
+ if (typeInformation.entityNameExp !== undefined && typeInformation.entityNameExp !== '') {
676
+ try {
677
+ logger.debug(context, 'sendUpdateValueNgsi2 entityNameExp %j ', typeInformation.entityNameExp);
678
+ entityName = expressionPlugin.applyExpression(typeInformation.entityNameExp, ctxt, typeInformation);
679
+ payload.entities[0].id = entityName;
680
+ ctxt['entity_name'] = entityName;
681
+ } catch (e) {
682
+ logger.debug(
683
+ context,
684
+ 'Error evaluating expression for entityName: %s with context: %s',
685
+ typeInformation.entityNameExp,
686
+ ctxt
687
+ );
688
+ }
689
+ }
690
+
678
691
  logger.debug(context, 'sendUpdateValueNgsi2 currentEntity sorted %j ', currentEntity);
679
692
  let timestampValue = undefined;
680
693
  // Loop for each final attribute to apply alias, multientity and expressions
@@ -745,9 +758,14 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca
745
758
  if (expressionPlugin.contextAvailable(attr.expression, ctxt, typeInformation)) {
746
759
  res = expressionPlugin.applyExpression(attr.expression, ctxt, typeInformation);
747
760
  if (
748
- // By default undefined is equivalent to null: should not progress
749
- (attr.skipValue === undefined && res === null) ||
750
- (attr.skipValue !== undefined && res === attr.skipValue)
761
+ // By default undefined is handled like null: should not progress
762
+ // Some op results (like nonexistent * 2) are a kind of null with a number type
763
+ // but NaN value
764
+ (attr.skipValue === undefined &&
765
+ (res === null || (typeof res === 'number' && isNaN(res)))) ||
766
+ (attr.skipValue !== undefined &&
767
+ (res === attr.skipValue ||
768
+ (typeof res === 'number' && isNaN(res) && attr.skipValue === null)))
751
769
  ) {
752
770
  logger.debug(
753
771
  context,
@@ -970,19 +988,10 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca
970
988
  // only in the first case
971
989
  if (options.json.entities.length === 1) {
972
990
  // recreate options object to use single entity update
973
- url = '/v2/entities/' + entityName + '/attrs';
974
- if (typeInformation && typeInformation.type) {
975
- url += '?type=' + typeInformation.type;
976
- }
991
+ url = '/v2/entities?options=upsert';
977
992
  options = NGSIUtils.createRequestObject(url, typeInformation, token);
978
993
  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 {
984
- options.method = 'PATCH';
985
- }
994
+ options.method = 'POST';
986
995
  } // else: keep current options object created for a batch update
987
996
  logger.debug(context, 'Updating device value in the Context Broker at [%s]', options.url);
988
997
  logger.debug(context, 'Using the following NGSI v2 request:\n\n%s\n\n', JSON.stringify(options, null, 4));
@@ -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
  };
@@ -254,6 +251,7 @@ function handleListDevices(req, res, next) {
254
251
  function handleGetDevice(req, res, next) {
255
252
  deviceService.getDevice(
256
253
  req.params.deviceId,
254
+ req.query.apikey,
257
255
  req.headers['fiware-service'],
258
256
  req.headers['fiware-servicepath'],
259
257
  function (error, device) {
@@ -272,8 +270,8 @@ function handleGetDevice(req, res, next) {
272
270
  * This middleware handles the removal of a particular device specified with the deviceId.
273
271
  */
274
272
  function handleRemoveDevice(req, res, next) {
275
- function getDevice(deviceId, service, subservice, callback) {
276
- deviceService.getDevice(deviceId, service, subservice, function (error, device) {
273
+ function getDevice(deviceId, apikey, service, subservice, callback) {
274
+ deviceService.getDevice(deviceId, apikey, service, subservice, function (error, device) {
277
275
  if (error) {
278
276
  callback(error);
279
277
  } else if (device) {
@@ -292,18 +290,25 @@ function handleRemoveDevice(req, res, next) {
292
290
  }
293
291
  }
294
292
 
295
- function unregisterDevice(deviceId, service, subservice, device, callback) {
296
- return deviceService.unregister(deviceId, service, subservice, callback);
293
+ function unregisterDevice(deviceId, apikey, service, subservice, device, callback) {
294
+ return deviceService.unregister(deviceId, apikey, service, subservice, callback);
297
295
  }
298
296
 
299
297
  async.waterfall(
300
298
  [
301
299
  apply(statsRegistry.add, 'deviceRemovalRequests', 1),
302
- apply(getDevice, req.params.deviceId, req.headers['fiware-service'], req.headers['fiware-servicepath']),
300
+ apply(
301
+ getDevice,
302
+ req.params.deviceId,
303
+ req.query.apikey,
304
+ req.headers['fiware-service'],
305
+ req.headers['fiware-servicepath']
306
+ ),
303
307
  applyRemoveDeviceHandler,
304
308
  apply(
305
309
  unregisterDevice,
306
310
  req.params.deviceId,
311
+ req.query.apikey,
307
312
  req.headers['fiware-service'],
308
313
  req.headers['fiware-servicepath']
309
314
  )
@@ -337,6 +342,7 @@ function handleUpdateDevice(req, res, next) {
337
342
  } else {
338
343
  deviceService.getDevice(
339
344
  req.params.deviceId,
345
+ req.query.apikey,
340
346
  req.headers['fiware-service'],
341
347
  req.headers['fiware-servicepath'],
342
348
  function (error, device) {
@@ -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
  },
@@ -37,10 +37,6 @@
37
37
  "description": "list of lazy attributes of the devices",
38
38
  "type": "array"
39
39
  },
40
- "expressionLanguage": {
41
- "description": "Expression language used to for the group of devices",
42
- "type": "string"
43
- },
44
40
  "ngsiVersion": {
45
41
  "description": "NGSI Interface for this group of devices",
46
42
  "type": "string"
@@ -81,4 +77,4 @@
81
77
  }
82
78
  }
83
79
  }
84
- }
80
+ }
@@ -200,6 +200,10 @@
200
200
  "description": "Free form array of data to be appended to the target entity",
201
201
  "type": "array"
202
202
  },
203
+ "timestamp": {
204
+ "description": "Timestamp",
205
+ "type": "boolean"
206
+ },
203
207
  "explicitAttrs": {
204
208
  "description": "Flag to decide update of active attributes only"
205
209
  },