iotagent-node-lib 2.19.0 → 2.22.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 (67) hide show
  1. package/.nyc_output/33364de2-1199-4ec2-b33c-cae063ef8cc4.json +1 -0
  2. package/.nyc_output/processinfo/33364de2-1199-4ec2-b33c-cae063ef8cc4.json +1 -0
  3. package/.nyc_output/processinfo/index.json +1 -0
  4. package/.readthedocs.yml +3 -1
  5. package/CHANGES_NEXT_RELEASE +1 -0
  6. package/README.md +5 -56
  7. package/doc/Contribution.md +3 -3
  8. package/doc/advanced-topics.md +8 -41
  9. package/doc/api.md +14 -3
  10. package/doc/expressionLanguage.md +17 -0
  11. package/doc/northboundinteractions.md +40 -33
  12. package/doc/operations.md +8 -5
  13. package/doc/requirements.txt +4 -0
  14. package/{docs → doc}/roadmap.md +21 -6
  15. package/doc/usermanual.md +4 -4
  16. package/docker/Mosquitto/Dockerfile +28 -12
  17. package/docker/Mosquitto/README.md +8 -7
  18. package/docker/Mosquitto/startMosquitto.sh +8 -0
  19. package/lib/fiware-iotagent-lib.js +1 -2
  20. package/lib/jexlTranformsMap.js +3 -1
  21. package/lib/model/Group.js +2 -1
  22. package/lib/model/dbConn.js +4 -0
  23. package/lib/plugins/expressionPlugin.js +56 -21
  24. package/lib/plugins/multiEntity.js +43 -49
  25. package/lib/plugins/pluginUtils.js +16 -0
  26. package/lib/services/commands/commandService.js +29 -2
  27. package/lib/services/common/domain.js +6 -2
  28. package/lib/services/common/iotManagerService.js +2 -1
  29. package/lib/services/devices/deviceRegistryMemory.js +13 -2
  30. package/lib/services/devices/deviceRegistryMongoDB.js +15 -7
  31. package/lib/services/devices/deviceService.js +52 -16
  32. package/lib/services/groups/groupRegistryMongoDB.js +13 -12
  33. package/lib/services/ngsi/entities-NGSI-LD.js +13 -4
  34. package/lib/services/ngsi/entities-NGSI-v2.js +8 -6
  35. package/lib/services/ngsi/ngsiService.js +3 -3
  36. package/lib/services/northBound/contextServer-NGSI-LD.js +20 -1
  37. package/lib/services/northBound/contextServer-NGSI-v2.js +39 -30
  38. package/lib/services/northBound/contextServerUtils.js +10 -10
  39. package/lib/services/northBound/deviceProvisioningServer.js +4 -1
  40. package/lib/templates/createDevice.json +13 -2
  41. package/lib/templates/createDeviceLax.json +2 -3
  42. package/lib/templates/updateDevice.json +13 -2
  43. package/package.json +27 -33
  44. package/test/unit/examples/deviceProvisioningRequests/provisionMinimumDevice4.json +14 -0
  45. package/test/unit/mongodb/mongoDBUtils.js +2 -2
  46. package/test/unit/mongodb/mongodb-group-registry-test.js +1 -1
  47. package/test/unit/mongodb/mongodb-registry-test.js +2 -3
  48. package/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerIoTAgentCommands.json +2 -1
  49. package/test/unit/ngsi-ld/examples/contextRequests/updateContextLanguageProperties1.json +15 -0
  50. package/test/unit/ngsi-ld/lazyAndCommands/command-test.js +315 -1
  51. package/test/unit/ngsi-ld/ngsiService/languageProperties-test.js +112 -0
  52. package/test/unit/ngsi-mixed/provisioning/ngsi-versioning-test.js +1 -1
  53. package/test/unit/ngsiv2/examples/contextRequests/createMinimumProvisionedDevice4.json +8 -0
  54. package/test/unit/ngsiv2/examples/contextRequests/updateContextCommandStatus2.json +6 -0
  55. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin35.json +2 -0
  56. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin36.json +1 -0
  57. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin17.json +27 -0
  58. package/test/unit/ngsiv2/expressions/jexlBasedTransformations-test.js +63 -2
  59. package/test/unit/ngsiv2/lazyAndCommands/polling-commands-test.js +151 -0
  60. package/test/unit/ngsiv2/plugins/multientity-plugin_test.js +63 -0
  61. package/test/unit/ngsiv2/provisioning/device-provisioning-api_test.js +60 -0
  62. package/test/unit/ngsiv2/provisioning/updateProvisionedDevices-test.js +2 -1
  63. package/bin/agentConsole.js +0 -257
  64. package/bin/iotAgentTester.js +0 -44
  65. package/lib/command/commandLine.js +0 -918
  66. package/lib/command/migration.js +0 -176
  67. package/test/unit/general/migration-test.js +0 -257
@@ -38,6 +38,8 @@ const logger = require('logops');
38
38
  const config = require('../../commonConfig');
39
39
  const registrationUtils = require('./registrationUtils');
40
40
  const subscriptions = require('../ngsi/subscriptionService');
41
+ const expressionPlugin = require('./../../plugins/expressionPlugin');
42
+ const pluginUtils = require('./../../plugins/pluginUtils');
41
43
  const _ = require('underscore');
42
44
  const context = {
43
45
  op: 'IoTAgentNGSI.DeviceService'
@@ -214,7 +216,13 @@ function findConfigurationGroup(deviceObj, callback) {
214
216
  } else {
215
217
  config
216
218
  .getGroupRegistry()
217
- .findTypeSilently(deviceObj.service, deviceObj.subservice, deviceObj.type, deviceObj.apikey, handlerGroupFindByType);
219
+ .findTypeSilently(
220
+ deviceObj.service,
221
+ deviceObj.subservice,
222
+ deviceObj.type,
223
+ deviceObj.apikey,
224
+ handlerGroupFindByType
225
+ );
218
226
  }
219
227
  }
220
228
 
@@ -274,22 +282,32 @@ function registerDevice(deviceObj, callback) {
274
282
  }
275
283
 
276
284
  if (!deviceData.name) {
277
- let conjunction;
278
- if (configuration && configuration.defaultEntityNameConjunction !== undefined) {
279
- conjunction = configuration.defaultEntityNameConjunction;
285
+ if (configuration && configuration.entityNameExp !== undefined) {
286
+ // Add device ID, TYPE, S, SS to the context for the JEXL expression
287
+ let attrList = pluginUtils.getIdTypeServSubServiceFromDevice(deviceData);
288
+ attrList = deviceData.staticAttributes ? attrList.concat(deviceData.staticAttributes) : attrList;
289
+ let ctxt = expressionPlugin.extractContext(attrList, deviceData);
290
+ let entityName = expressionPlugin.applyExpression(configuration.entityNameExp, ctxt, deviceData);
291
+ deviceData.name = entityName ? entityName : configuration.entityNameExp;
280
292
  } else {
281
- conjunction = config.getConfig().defaultEntityNameConjunction;
282
- }
283
- deviceData.name = deviceData.type + conjunction + deviceData.id;
284
- if (config.checkNgsiLD(configuration)) {
285
- deviceData.name = 'urn:ngsi-ld:' + deviceData.type + conjunction + deviceData.id;
293
+ let conjunction;
294
+ if (configuration && configuration.defaultEntityNameConjunction !== undefined) {
295
+ conjunction = configuration.defaultEntityNameConjunction;
296
+ } else {
297
+ conjunction = config.getConfig().defaultEntityNameConjunction;
298
+ }
299
+ deviceData.name = deviceData.type + conjunction + deviceData.id;
300
+
301
+ if (config.checkNgsiLD(configuration)) {
302
+ deviceData.name = 'urn:ngsi-ld:' + deviceData.type + conjunction + deviceData.id;
303
+ }
304
+ logger.debug(
305
+ context,
306
+ 'Device name not found, falling back to deviceType%sdeviceId [%s]',
307
+ conjunction,
308
+ deviceData.name
309
+ );
286
310
  }
287
- logger.debug(
288
- context,
289
- 'Device name not found, falling back to deviceType%sdeviceId [%s]',
290
- conjunction,
291
- deviceData.name
292
- );
293
311
  }
294
312
 
295
313
  if (!configuration && config.getConfig().types[deviceData.type]) {
@@ -513,6 +531,18 @@ function getDeviceByName(deviceName, service, subservice, callback) {
513
531
  config.getRegistry().getByName(deviceName, service, subservice, callback);
514
532
  }
515
533
 
534
+ /**
535
+ * Retrieve a device from the registry based on its entity name and type
536
+ *
537
+ * @param {String} deviceName Name of the entity associated to a device.
538
+ * @param {String} deviceType Type of the entity associated to a device.
539
+ * @param {String} service Service the device belongs to.
540
+ * @param {String} subservice Division inside the service.
541
+ */
542
+ function getDeviceByNameAndType(deviceName, deviceType, service, subservice, callback) {
543
+ config.getRegistry().getByNameAndType(deviceName, deviceType, service, subservice, callback);
544
+ }
545
+
516
546
  /**
517
547
  * Retrieve a device from the registry based on the value of a given attribute.
518
548
  *
@@ -581,7 +611,12 @@ function findOrCreate(deviceId, group, callback) {
581
611
  callback(error, device, group);
582
612
  });
583
613
  } else {
584
- logger.info(context, 'Device %j not provisioned due autoprovision is disabled by its conf %j', newDevice, group);
614
+ logger.info(
615
+ context,
616
+ 'Device %j not provisioned due autoprovision is disabled by its conf %j',
617
+ newDevice,
618
+ group
619
+ );
585
620
  callback(new errors.DeviceNotFound(deviceId));
586
621
  }
587
622
  } else {
@@ -632,6 +667,7 @@ exports.getDevice = intoTrans(context, checkRegistry)(getDevice);
632
667
  exports.getDeviceSilently = intoTrans(context, checkRegistry)(getDeviceSilently);
633
668
  exports.getDevicesByAttribute = intoTrans(context, checkRegistry)(getDevicesByAttribute);
634
669
  exports.getDeviceByName = intoTrans(context, checkRegistry)(getDeviceByName);
670
+ exports.getDeviceByNameAndType = intoTrans(context, checkRegistry)(getDeviceByNameAndType);
635
671
  exports.register = intoTrans(context, registerDevice);
636
672
  exports.updateRegister = intoTrans(context, updateRegisterDevice);
637
673
  exports.unregister = intoTrans(context, unregisterDevice);
@@ -57,7 +57,8 @@ const attributeList = [
57
57
  'explicitAttrs',
58
58
  'expressionLanguage',
59
59
  'defaultEntityNameConjunction',
60
- 'ngsiVersion'
60
+ 'ngsiVersion',
61
+ 'entityNameExp'
61
62
  ];
62
63
 
63
64
  /**
@@ -299,21 +300,21 @@ function clear(callback) {
299
300
  dbService.db.db.dropDatabase(callback);
300
301
  }
301
302
 
302
- exports.create = alarmsInt(constants.MONGO_ALARM, intoTrans(context, createGroup));
303
- exports.list = alarmsInt(constants.MONGO_ALARM, intoTrans(context, listGroups));
304
- exports.init = alarmsInt(constants.MONGO_ALARM, intoTrans(context, init));
305
- exports.find = alarmsInt(constants.MONGO_ALARM, intoTrans(context, find));
303
+ exports.create = alarmsInt(constants.MONGO_ALARM + '_01', intoTrans(context, createGroup));
304
+ exports.list = alarmsInt(constants.MONGO_ALARM + '_02', intoTrans(context, listGroups));
305
+ exports.init = alarmsInt(constants.MONGO_ALARM + '_03', intoTrans(context, init));
306
+ exports.find = alarmsInt(constants.MONGO_ALARM + '_04', intoTrans(context, find));
306
307
  exports.findType = alarmsInt(
307
- constants.MONGO_ALARM,
308
+ constants.MONGO_ALARM + '_05',
308
309
  intoTrans(context, findBy(['service', 'subservice', 'type', 'apikey']))
309
310
  );
310
311
  exports.findTypeSilently = intoTrans(context, findBy(['service', 'subservice', 'type', 'apikey']));
311
312
  exports.findSilently = intoTrans(context, findBy(['service', 'subservice', 'apikey']));
312
- exports.findBy = alarmsInt(constants.MONGO_ALARM, intoTrans(context, findBy));
313
- exports.get = alarmsInt(constants.MONGO_ALARM, intoTrans(context, findBy(['resource', 'apikey'])));
313
+ exports.findBy = alarmsInt(constants.MONGO_ALARM + '_06', intoTrans(context, findBy));
314
+ exports.get = alarmsInt(constants.MONGO_ALARM + '_07', intoTrans(context, findBy(['resource', 'apikey'])));
314
315
  exports.getSilently = intoTrans(context, findBy(['resource', 'apikey']));
315
- exports.getType = alarmsInt(constants.MONGO_ALARM, intoTrans(context, findBy(['type'])));
316
+ exports.getType = alarmsInt(constants.MONGO_ALARM + '_08', intoTrans(context, findBy(['type'])));
316
317
  exports.getTypeSilently = intoTrans(context, findBy(['type']));
317
- exports.update = alarmsInt(constants.MONGO_ALARM, intoTrans(context, update));
318
- exports.remove = alarmsInt(constants.MONGO_ALARM, intoTrans(context, remove));
319
- exports.clear = alarmsInt(constants.MONGO_ALARM, intoTrans(context, clear));
318
+ exports.update = alarmsInt(constants.MONGO_ALARM + '_09', intoTrans(context, update));
319
+ exports.remove = alarmsInt(constants.MONGO_ALARM + '_10', intoTrans(context, remove));
320
+ exports.clear = alarmsInt(constants.MONGO_ALARM + '_11', intoTrans(context, clear));
@@ -160,6 +160,13 @@ function convertAttrNGSILD(attr) {
160
160
  delete obj.value;
161
161
  break;
162
162
 
163
+ // LanguageProperties
164
+ case 'languageproperty':
165
+ obj.type = 'LanguageProperty';
166
+ obj.languageMap = attr.value;
167
+ delete obj.value;
168
+ break;
169
+
163
170
  default:
164
171
  obj.value = { '@type': attr.type, '@value': attr.value };
165
172
  }
@@ -410,8 +417,9 @@ function addLinkedEntities(typeInformation, json) {
410
417
  * @param {Object} typeInformation Configuration information for the device.
411
418
  */
412
419
  function removeHiddenAttrsFromMultiEntity(entities, typeInformation) {
413
- var explicitAttrsList = [];
420
+ let explicitAttrsList;
414
421
  if (typeInformation.explicitAttrs) {
422
+ explicitAttrsList = [];
415
423
  explicitAttrsList.push('type');
416
424
  explicitAttrsList.push('id');
417
425
  if (typeof typeInformation.explicitAttrs === 'boolean') {
@@ -437,7 +445,7 @@ function removeHiddenAttrsFromMultiEntity(entities, typeInformation) {
437
445
  });
438
446
  }
439
447
  }
440
- if (explicitAttrsList.length > 0) {
448
+ if (explicitAttrsList && explicitAttrsList.length >= 0) {
441
449
  entities.forEach((entity) => {
442
450
  const hidden = _.difference(_.keys(entity), explicitAttrsList);
443
451
  hidden.forEach((attr) => {
@@ -457,8 +465,9 @@ function removeHiddenAttrsFromMultiEntity(entities, typeInformation) {
457
465
  function removeHiddenAttrs(result, typeInformation) {
458
466
  delete result.id;
459
467
  delete result.type;
460
- var explicitAttrsList = [];
468
+ let explicitAttrsList;
461
469
  if (typeInformation.explicitAttrs && typeof typeInformation.explicitAttrs === 'boolean') {
470
+ explicitAttrsList = [];
462
471
  if (typeInformation.timestamp) {
463
472
  explicitAttrsList.push(constants.TIMESTAMP_ATTRIBUTE);
464
473
  }
@@ -478,7 +487,7 @@ function removeHiddenAttrs(result, typeInformation) {
478
487
  const res = jexlParser.parse(typeInformation.explicitAttrs, ctx);
479
488
  explicitAttrsList = res;
480
489
  }
481
- if (explicitAttrsList.length > 0) {
490
+ if (explicitAttrsList && explicitAttrsList.length >= 0) {
482
491
  const hidden = _.difference(_.keys(result), explicitAttrsList);
483
492
  hidden.forEach((attr) => {
484
493
  delete result[attr];
@@ -321,8 +321,9 @@ function sendQueryValueNgsi2(entityName, attributes, typeInformation, token, cal
321
321
  * @param {Object} typeInformation Configuration information for the device.
322
322
  */
323
323
  function removeHiddenAttrsFromMultiEntity(entities, typeInformation) {
324
- var explicitAttrsList = [];
324
+ let explicitAttrsList;
325
325
  if (typeInformation.explicitAttrs) {
326
+ explicitAttrsList = [];
326
327
  explicitAttrsList.push('type');
327
328
  explicitAttrsList.push('id');
328
329
  if (typeof typeInformation.explicitAttrs === 'boolean') {
@@ -349,10 +350,10 @@ function removeHiddenAttrsFromMultiEntity(entities, typeInformation) {
349
350
  });
350
351
  }
351
352
  }
352
- if (explicitAttrsList.length > 0) {
353
- logger.debug(context, 'removeHiddenAttrsFromMultiEntity %s', explicitAttrsList);
353
+ if (explicitAttrsList && explicitAttrsList.length >= 0) {
354
354
  entities.forEach((entity) => {
355
355
  const hidden = _.difference(_.keys(entity), explicitAttrsList);
356
+ logger.debug(context, 'removeHiddenAttrsFromMultiEntity %s from entity %s', hidden, entity);
356
357
  hidden.forEach((attr) => {
357
358
  delete entity[attr];
358
359
  });
@@ -369,8 +370,9 @@ function removeHiddenAttrsFromMultiEntity(entities, typeInformation) {
369
370
  function removeHiddenAttrs(result, typeInformation) {
370
371
  delete result.id;
371
372
  delete result.type;
372
- var explicitAttrsList = [];
373
+ let explicitAttrsList;
373
374
  if (typeInformation.explicitAttrs && typeof typeInformation.explicitAttrs === 'boolean') {
375
+ explicitAttrsList = [];
374
376
  if (typeInformation.timestamp) {
375
377
  explicitAttrsList.push(constants.TIMESTAMP_ATTRIBUTE);
376
378
  }
@@ -390,9 +392,9 @@ function removeHiddenAttrs(result, typeInformation) {
390
392
  const res = jexlParser.applyExpression(typeInformation.explicitAttrs, ctx, typeInformation);
391
393
  explicitAttrsList = res;
392
394
  }
393
- if (explicitAttrsList.length > 0) {
394
- logger.debug(context, 'removeHiddenAttrs %s', explicitAttrsList);
395
+ if (explicitAttrsList && explicitAttrsList.length >= 0) {
395
396
  const hidden = _.difference(_.keys(result), explicitAttrsList);
397
+ logger.debug(context, 'removeHiddenAttrs %s', hidden);
396
398
  hidden.forEach((attr) => {
397
399
  delete result[attr];
398
400
  });
@@ -133,7 +133,7 @@ function executeWithDeviceInformation(operationFunction) {
133
133
  deviceInformation
134
134
  );
135
135
  const currentType = type ? type : deviceInformation.type;
136
- config.getGroupRegistry().getType(currentType, function (error, deviceGroup) {
136
+ config.getGroupRegistry().getTypeSilently(currentType, function (error, deviceGroup) {
137
137
  let typeInformation;
138
138
  const configDeviceInfo = config.getConfig().types[currentType];
139
139
  if (error) {
@@ -177,7 +177,7 @@ function executeWithDeviceInformation(operationFunction) {
177
177
 
178
178
  /**
179
179
  * Update the result of a command in the Context Broker. The result of the command has two components: the result
180
- * of the command itself will be represented with the sufix '_result' in the entity while the status is updated in the
180
+ * of the command itself will be represented with the sufix '_info' in the entity while the status is updated in the
181
181
  * attribute with the '_status' sufix.
182
182
  *
183
183
  * @param {String} entityName Name of the entity holding the command.
@@ -234,7 +234,7 @@ function setCommandResult(
234
234
  }
235
235
 
236
236
  if (commandInfo.length === 1) {
237
- exports.update(entityName, resource, apikey, attributes, typeInformation, callback);
237
+ exports.update(entityName, typeInformation.type, apikey, attributes, typeInformation, callback);
238
238
  } else {
239
239
  callback(new errors.CommandNotFound(commandName));
240
240
  }
@@ -42,7 +42,8 @@ const notificationTemplateNgsiLD = require('../../templates/notificationTemplate
42
42
  const contextServerUtils = require('./contextServerUtils');
43
43
  const ngsiLD = require('../ngsi/entities-NGSI-LD');
44
44
 
45
- const updatePaths = ['/ngsi-ld/v1/entities/:entity/attrs/:attr'];
45
+ const overwritePaths = ['/ngsi-ld/v1/entities/:entity/attrs', '/ngsi-ld/v1/entities/:entity/attrs/:attr'];
46
+ const updatePaths = ['/ngsi-ld/v1/entities/:entity/attrs', '/ngsi-ld/v1/entities/:entity/attrs/:attr'];
46
47
  const queryPaths = ['/ngsi-ld/v1/entities/:entity'];
47
48
 
48
49
  /**
@@ -55,8 +56,10 @@ const queryPaths = ['/ngsi-ld/v1/entities/:entity'];
55
56
  function generateUpdateActionsNgsiLD(req, contextElement, callback) {
56
57
  let entityId;
57
58
  let entityType;
59
+
58
60
  const attribute = req.params.attr;
59
61
  const value = req.body.value;
62
+ const incomingAttrs = !req.params.attr ? _.keys(req.body) : [];
60
63
 
61
64
  if (contextElement.id && contextElement.type) {
62
65
  entityId = contextElement.id;
@@ -79,6 +82,13 @@ function generateUpdateActionsNgsiLD(req, contextElement, callback) {
79
82
  name: attribute
80
83
  });
81
84
  found = true;
85
+ } else if (incomingAttrs.includes(device.commands[j].name)) {
86
+ commands.push({
87
+ type: device.commands[j].type,
88
+ value: req.body[device.commands[j].name].value,
89
+ name: device.commands[j].name
90
+ });
91
+ found = true;
82
92
  }
83
93
  }
84
94
  }
@@ -573,6 +583,15 @@ function loadContextRoutesNGSILD(router) {
573
583
  updateErrorHandlingNgsiLD
574
584
  ]);
575
585
  }
586
+
587
+ for (i = 0; i < overwritePaths.length; i++) {
588
+ router.put(overwritePaths[i], [
589
+ middlewares.ensureType,
590
+ middlewares.validateJson(updateContextTemplateNgsiLD),
591
+ handleUpdateNgsiLD,
592
+ updateErrorHandlingNgsiLD
593
+ ]);
594
+ }
576
595
  for (i = 0; i < queryPaths.length; i++) {
577
596
  router.get(queryPaths[i], [handleQueryNgsiLD, queryErrorHandlingNgsiLD]);
578
597
  }
@@ -159,29 +159,32 @@ function generateUpdateActionsNgsi2(req, contextElement, callback) {
159
159
  callback(null, updateActions);
160
160
  }
161
161
 
162
- deviceService.getDeviceByName(entityId, req.headers['fiware-service'], req.headers['fiware-servicepath'], function (
163
- error,
164
- deviceObj
165
- ) {
166
- if (error) {
167
- callback(error);
168
- } else {
169
- async.waterfall(
170
- [
171
- apply(deviceService.findConfigurationGroup, deviceObj),
172
- apply(
173
- deviceService.mergeDeviceWithConfiguration,
174
- ['lazy', 'internalAttributes', 'active', 'staticAttributes', 'commands', 'subscriptions'],
175
- [null, null, [], [], [], [], []],
176
- deviceObj
177
- ),
178
- splitUpdates,
179
- createActionsArray
180
- ],
181
- callback
182
- );
162
+ deviceService.getDeviceByNameAndType(
163
+ entityId,
164
+ entityType,
165
+ req.headers['fiware-service'],
166
+ req.headers['fiware-servicepath'],
167
+ function (error, deviceObj) {
168
+ if (error) {
169
+ callback(error);
170
+ } else {
171
+ async.waterfall(
172
+ [
173
+ apply(deviceService.findConfigurationGroup, deviceObj),
174
+ apply(
175
+ deviceService.mergeDeviceWithConfiguration,
176
+ ['lazy', 'internalAttributes', 'active', 'staticAttributes', 'commands', 'subscriptions'],
177
+ [null, null, [], [], [], [], []],
178
+ deviceObj
179
+ ),
180
+ splitUpdates,
181
+ createActionsArray
182
+ ],
183
+ callback
184
+ );
185
+ }
183
186
  }
184
- });
187
+ );
185
188
  }
186
189
 
187
190
  /** Express middleware to manage incoming update requests using NGSIv2.
@@ -214,7 +217,11 @@ function handleUpdateNgsi2(req, res, next) {
214
217
  }
215
218
  );
216
219
  } else {
217
- logger.error(context, 'Tried to handle an update request before the update handler was stablished.');
220
+ logger.error(
221
+ context,
222
+ 'Tried to handle an update request [%j] before the update handler was stablished.',
223
+ req.body
224
+ );
218
225
 
219
226
  const errorNotFound = new Error({
220
227
  message: 'Update handler not found'
@@ -238,8 +245,7 @@ function defaultQueryHandlerNgsi2(id, type, service, subservice, attributes, cal
238
245
  type,
239
246
  id
240
247
  };
241
-
242
- deviceService.getDeviceByName(id, service, subservice, function (error, ngsiDevice) {
248
+ deviceService.getDeviceByNameAndType(id, type, service, subservice, function (error, ngsiDevice) {
243
249
  if (error) {
244
250
  callback(error);
245
251
  } else {
@@ -285,8 +291,9 @@ function handleNotificationNgsi2(req, res, next) {
285
291
  }
286
292
  }
287
293
  }
288
- deviceService.getDeviceByName(
294
+ deviceService.getDeviceByNameAndType(
289
295
  dataElement.id,
296
+ dataElement.type,
290
297
  req.headers['fiware-service'],
291
298
  req.headers['fiware-servicepath'],
292
299
  function (error, device) {
@@ -378,7 +385,7 @@ function queryErrorHandlingNgsi2(error, req, res, next) {
378
385
  function updateErrorHandlingNgsi2(error, req, res, next) {
379
386
  let code = 500;
380
387
 
381
- logger.debug(context, 'Update NGSIv2 error [%s] handing request: %s', error.name, error.message);
388
+ logger.debug(context, 'Update NGSIv2 error [%j] handing request: %j', error, req.body);
382
389
 
383
390
  if (error.code && String(error.code).match(/^[2345]\d\d$/)) {
384
391
  code = error.code;
@@ -448,6 +455,7 @@ function handleQueryNgsi2(req, res, next) {
448
455
  }
449
456
 
450
457
  deviceService.findConfigurationGroup(device, function (error, group) {
458
+ logger.debug(context, 'finishQueryForDevice %j', group);
451
459
  const executeCompleteAttributes = apply(completeAttributes, attributes, group);
452
460
  const executeQueryHandler = apply(
453
461
  actualHandler,
@@ -474,8 +482,9 @@ function handleQueryNgsi2(req, res, next) {
474
482
 
475
483
  if (contextEntity.id) {
476
484
  getFunction = apply(
477
- deviceService.getDeviceByName,
485
+ deviceService.getDeviceByNameAndType,
478
486
  contextEntity.id,
487
+ contextEntity.type,
479
488
  req.headers['fiware-service'],
480
489
  req.headers['fiware-servicepath']
481
490
  );
@@ -504,7 +513,7 @@ function handleQueryNgsi2(req, res, next) {
504
513
  } else {
505
514
  deviceList = [innerDevice];
506
515
  }
507
-
516
+ logger.debug(context, 'handleFindDevice from %j', deviceList);
508
517
  async.map(
509
518
  deviceList,
510
519
  async.apply(finishQueryForDevice, attributes, contextEntity, actualHandler),
@@ -528,7 +537,7 @@ function handleQueryNgsi2(req, res, next) {
528
537
  logger.debug(context, 'There was an error handling the query: %s.', error);
529
538
  next(error);
530
539
  } else {
531
- logger.debug(context, 'Query from [%s] handled successfully.', req.get('host'));
540
+ logger.debug(context, 'Query from [%s] handled successfully. req %s', req.get('host'), req);
532
541
  res.status(200).json(result);
533
542
  }
534
543
  }
@@ -41,10 +41,10 @@ const commands = require('../commands/commandService');
41
41
  * @return {String} The Tenant decribed in the request headers
42
42
  */
43
43
  function getLDTenant(req) {
44
- if (req.headers['NGSILD-Tenant']) {
45
- return req.headers['NGSILD-Tenant'];
46
- } else if (req.headers['fiware-service']) {
47
- return req.headers['fiware-service'];
44
+ if (req.header('NGSILD-Tenant')) {
45
+ return req.header('NGSILD-Tenant');
46
+ } else if (req.header('fiware-service')) {
47
+ return req.header('fiware-service');
48
48
  }
49
49
  return config.getConfig().contextBroker.fallbackTenant;
50
50
  }
@@ -56,10 +56,10 @@ function getLDTenant(req) {
56
56
  * obliged to offer service headers - this is still being defined in the NGSI-LD specifications.
57
57
  */
58
58
  function getLDPath(req) {
59
- if (req.headers['NGSILD-Path']) {
60
- return req.headers['NGSILD-Path'];
61
- } else if (req.headers['fiware-servicepath']) {
62
- return req.headers['fiware-servicepath'];
59
+ if (req.header('NGSILD-Path')) {
60
+ return req.header('NGSILD-path');
61
+ } else if (req.header('fiware-servicepath')) {
62
+ return req.header('fiware-servicepath');
63
63
  }
64
64
  return config.getConfig().contextBroker.fallbackPath;
65
65
  }
@@ -91,7 +91,7 @@ function executeUpdateSideEffects(device, id, type, service, subservice, attribu
91
91
  ];
92
92
 
93
93
  sideEffects.push(
94
- apply(ngsi.update, device.name, device.resource, device.apikey, newAttributes, device)
94
+ apply(ngsi.update, device.name, device.type, device.apikey, newAttributes, device)
95
95
  );
96
96
  }
97
97
  }
@@ -112,7 +112,7 @@ function executeUpdateSideEffects(device, id, type, service, subservice, attribu
112
112
  * @param {Array} attributes List of attributes to update with their types and values.
113
113
  */
114
114
  function pushCommandsToQueue(device, id, type, service, subservice, attributes, callback) {
115
- async.map(attributes, apply(commands.add, service, subservice, device.id), callback);
115
+ async.map(attributes, apply(commands.addCmd, service, subservice, device), callback);
116
116
  }
117
117
 
118
118
  exports.notificationMiddlewares = [];
@@ -63,7 +63,8 @@ const provisioningAPITranslation = {
63
63
  autoprovision: 'autoprovision',
64
64
  explicitAttrs: 'explicitAttrs',
65
65
  expressionLanguage: 'expressionLanguage',
66
- ngsiVersion: 'ngsiVersion'
66
+ ngsiVersion: 'ngsiVersion',
67
+ entityNameExp: 'entityNameExp'
67
68
  };
68
69
 
69
70
  /**
@@ -184,6 +185,8 @@ function attributeToProvisioningAPIFormat(attribute) {
184
185
  entity_name: attribute.entity_name,
185
186
  entity_type: attribute.entity_type,
186
187
  mqtt: attribute.mqtt,
188
+ payloadType: attribute.payloadType,
189
+ contentType: attribute.contentType,
187
190
  metadata: attribute.metadata
188
191
  };
189
192
  }
@@ -41,8 +41,7 @@
41
41
  "type": "string"
42
42
  },
43
43
  "explicitAttrs": {
44
- "description": "Flag about only provisioned attributes will be processed to Context Broker",
45
- "type": "boolean"
44
+ "description": "Flag about only provisioned attributes will be processed to Context Broker"
46
45
  },
47
46
  "ngsiVersion": {
48
47
  "description": "NGSI Interface for this device",
@@ -173,6 +172,18 @@
173
172
  "type": "string",
174
173
  "pattern": "^([^<>();'=\"]+)*$"
175
174
  },
175
+ "expression": {
176
+ "description": "Optional expression for command transformation",
177
+ "type": "string"
178
+ },
179
+ "payloadType": {
180
+ "description": "Payload type",
181
+ "type": "string"
182
+ },
183
+ "contentType": {
184
+ "description": "Content type",
185
+ "type": "string"
186
+ },
176
187
  "mqtt": {
177
188
  "description": "Mqtt properties",
178
189
  "type": "object",
@@ -41,8 +41,7 @@
41
41
  "type": "boolean"
42
42
  },
43
43
  "explicitAttrs": {
44
- "description": "Flag about only provisioned attributes will be processed to Context Broker",
45
- "type": "boolean"
44
+ "description": "Flag about only provisioned attributes will be processed to Context Broker"
46
45
  },
47
46
  "ngsiVersion": {
48
47
  "description": "NGSI Interface for this device",
@@ -181,4 +180,4 @@
181
180
  }
182
181
  }
183
182
  }
184
- }
183
+ }
@@ -158,6 +158,18 @@
158
158
  "type": "string",
159
159
  "pattern": "^([^<>();'=\"]+)*$"
160
160
  },
161
+ "expression": {
162
+ "description": "Optional expression for command transformation",
163
+ "type": "string"
164
+ },
165
+ "payloadType": {
166
+ "description": "Payload type",
167
+ "type": "string"
168
+ },
169
+ "contentType": {
170
+ "description": "Content type",
171
+ "type": "string"
172
+ },
161
173
  "mqtt": {
162
174
  "description": "Mqtt properties",
163
175
  "type": "object",
@@ -186,8 +198,7 @@
186
198
  "type": "array"
187
199
  },
188
200
  "explicitAttrs": {
189
- "description": "Flag to decide update of active attributes only",
190
- "type": "Boolean"
201
+ "description": "Flag to decide update of active attributes only"
191
202
  },
192
203
  "ngsiVersion": {
193
204
  "description": "NGSI Interface for this device",