iotagent-node-lib 3.4.4 → 4.0.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 (93) hide show
  1. package/README.md +4 -0
  2. package/doc/admin.md +1 -13
  3. package/doc/api.md +116 -18
  4. package/doc/devel/architecture.md +0 -12
  5. package/doc/index.md +1 -1
  6. package/doc/roadmap.md +22 -10
  7. package/lib/commonConfig.js +0 -11
  8. package/lib/model/Device.js +2 -1
  9. package/lib/model/Group.js +2 -1
  10. package/lib/model/dbConn.js +22 -11
  11. package/lib/plugins/expressionPlugin.js +0 -5
  12. package/lib/plugins/jexlParser.js +15 -31
  13. package/lib/services/common/genericMiddleware.js +14 -2
  14. package/lib/services/common/iotManagerService.js +2 -1
  15. package/lib/services/devices/deviceRegistryMongoDB.js +3 -1
  16. package/lib/services/devices/deviceService.js +16 -21
  17. package/lib/services/devices/devices-NGSI-LD.js +5 -98
  18. package/lib/services/devices/devices-NGSI-mixed.js +0 -14
  19. package/lib/services/devices/devices-NGSI-v2.js +3 -0
  20. package/lib/services/groups/groupRegistryMemory.js +0 -25
  21. package/lib/services/groups/groupRegistryMongoDB.js +20 -19
  22. package/lib/services/groups/groupService.js +3 -14
  23. package/lib/services/ngsi/entities-NGSI-LD.js +81 -6
  24. package/lib/services/ngsi/entities-NGSI-v2.js +303 -698
  25. package/lib/services/ngsi/ngsiUtils.js +0 -30
  26. package/lib/services/northBound/deviceProvisioningServer.js +6 -3
  27. package/lib/templates/createDevice.json +4 -0
  28. package/lib/templates/createDeviceLax.json +4 -0
  29. package/lib/templates/deviceGroup.json +4 -0
  30. package/lib/templates/updateDevice.json +4 -0
  31. package/lib/templates/updateDeviceLax.json +4 -0
  32. package/package.json +6 -2
  33. package/test/functional/README.md +378 -0
  34. package/test/functional/config-test.js +70 -0
  35. package/test/functional/functional-tests-runner.js +126 -0
  36. package/test/functional/functional-tests.js +241 -0
  37. package/test/functional/testCases.js +2944 -0
  38. package/test/functional/testUtils.js +251 -0
  39. package/test/tools/utils.js +25 -0
  40. package/test/unit/mongodb/mongodb-connectionoptions-test.js +35 -22
  41. package/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDeviceWithGroupAndStatic2.json +3 -34
  42. package/test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin6.json +8 -1
  43. package/test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin7.json +1 -4
  44. package/test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin8.json +1 -6
  45. package/test/unit/ngsi-ld/general/contextBrokerOAuthSecurityAccess-test.js +67 -87
  46. package/test/unit/ngsi-ld/lazyAndCommands/command-test.js +7 -13
  47. package/test/unit/ngsi-ld/lazyAndCommands/merge-patch-test.js +43 -43
  48. package/test/unit/ngsi-ld/lazyAndCommands/polling-commands-test.js +19 -29
  49. package/test/unit/ngsi-ld/ngsiService/languageProperties-test.js +0 -1
  50. package/test/unit/ngsi-ld/ngsiService/subscriptions-test.js +35 -46
  51. package/test/unit/ngsi-ld/plugins/alias-plugin_test.js +8 -9
  52. package/test/unit/ngsi-ld/provisioning/device-provisioning-api_test.js +96 -221
  53. package/test/unit/ngsi-ld/provisioning/device-registration_test.js +18 -27
  54. package/test/unit/ngsi-ld/provisioning/device-update-registration_test.js +8 -16
  55. package/test/unit/ngsi-ld/provisioning/updateProvisionedDevices-test.js +0 -13
  56. package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin8.json +4 -4
  57. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin29b.json +8 -0
  58. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin30.json +1 -1
  59. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin32.json +0 -6
  60. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin34.json +8 -0
  61. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin34b.json +14 -0
  62. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin35.json +1 -11
  63. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin36b.json +13 -0
  64. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin37.json +8 -0
  65. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin41.json +1 -11
  66. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin10b.json +37 -0
  67. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin11.json +0 -4
  68. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin15.json +0 -4
  69. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin16.json +0 -4
  70. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin25.json +4 -0
  71. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin4.json +0 -3
  72. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin5.json +10 -12
  73. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin6.json +0 -4
  74. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin7.json +1 -5
  75. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin8.json +8 -12
  76. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin2.json +0 -4
  77. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin3.json +0 -8
  78. package/test/unit/ngsiv2/examples/contextRequests/updateContextStaticAttributesMetadata.json +7 -1
  79. package/test/unit/ngsiv2/expressions/jexlBasedTransformations-test.js +898 -28
  80. package/test/unit/ngsiv2/ngsiService/active-devices-test.js +0 -4
  81. package/test/unit/ngsiv2/ngsiService/staticAttributes-test.js +267 -0
  82. package/test/unit/ngsiv2/plugins/alias-plugin_test.js +19 -21
  83. package/test/unit/ngsiv2/plugins/multientity-plugin_test.js +21 -24
  84. package/test/unit/ngsiv2/provisioning/device-group-utils-test.js +1 -21
  85. package/test/unit/ngsiv2/provisioning/device-provisioning-api_test.js +4 -6
  86. package/test/unit/ngsi-ld/ngsiService/autocast-test.js +0 -438
  87. package/test/unit/ngsi-ld/ngsiService/geoproperties-test.js +0 -381
  88. package/test/unit/ngsi-ld/provisioning/singleConfigurationMode-test.js +0 -311
  89. package/test/unit/ngsiv2/ngsiService/autocast-test.js +0 -325
  90. package/test/unit/ngsiv2/ngsiService/geoproperties-test.js +0 -427
  91. package/test/unit/ngsiv2/plugins/compress-timestamp-plugin_test.js +0 -217
  92. package/test/unit/ngsiv2/plugins/timestamp-processing-plugin_test.js +0 -119
  93. package/test/unit/ngsiv2/provisioning/singleConfigurationMode-test.js +0 -309
@@ -60,7 +60,8 @@ function register(callback) {
60
60
  explicitAttrs: service.explicitAttrs,
61
61
  defaultEntityNameConjunction: service.defaultEntityNameConjunction,
62
62
  ngsiVersion: service.ngsiVersion,
63
- entityNameExp: service.entityNameExp
63
+ entityNameExp: service.entityNameExp,
64
+ payloadType: service.payloadType
64
65
  };
65
66
  }
66
67
 
@@ -55,7 +55,8 @@ const attributeList = [
55
55
  'polling',
56
56
  'timestamp',
57
57
  'explicitAttrs',
58
- 'ngsiVersion'
58
+ 'ngsiVersion',
59
+ 'payloadType'
59
60
  ];
60
61
 
61
62
  /**
@@ -316,6 +317,7 @@ function update(device, callback) {
316
317
  data.explicitAttrs = device.explicitAttrs;
317
318
  data.ngsiVersion = device.ngsiVersion;
318
319
  data.timestamp = device.timestamp;
320
+ data.payloadType = device.payloadType;
319
321
 
320
322
  /* eslint-disable-next-line new-cap */
321
323
  const deviceObj = new Device.model(data);
@@ -173,13 +173,18 @@ function mergeDeviceWithConfiguration(fields, defaults, deviceData, configuratio
173
173
  if (configuration && configuration.entityNameExp !== undefined) {
174
174
  deviceData.entityNameExp = configuration.entityNameExp;
175
175
  }
176
+ if (configuration && configuration.timestamp !== undefined && deviceData.timestamp === undefined) {
177
+ deviceData.timestamp = configuration.timestamp;
178
+ }
179
+ if (configuration && configuration.payloadType !== undefined && deviceData.payloadType === undefined) {
180
+ deviceData.payloadType = configuration.payloadType;
181
+ }
176
182
  logger.debug(context, 'deviceData after merge with conf: %j', deviceData);
177
183
  callback(null, deviceData);
178
184
  }
179
185
 
180
186
  /**
181
- * Find the configuration group belonging to a given device, with a different criteria depending on whether the
182
- * agent is in single configuration mode or node.
187
+ * Find the configuration group belonging to a given device
183
188
  *
184
189
  * @param {Object} deviceObj Device data.
185
190
  */
@@ -206,19 +211,15 @@ function findConfigurationGroup(deviceObj, callback) {
206
211
  callback(null, effectiveGroup);
207
212
  }
208
213
 
209
- if (config.getConfig().singleConfigurationMode === true) {
210
- config.getGroupRegistry().find(deviceObj.service, deviceObj.subservice, handlerGroupFind);
211
- } else {
212
- config
213
- .getGroupRegistry()
214
- .findTypeSilently(
215
- deviceObj.service,
216
- deviceObj.subservice,
217
- deviceObj.type,
218
- deviceObj.apikey,
219
- handlerGroupFindByType
220
- );
221
- }
214
+ config
215
+ .getGroupRegistry()
216
+ .findTypeSilently(
217
+ deviceObj.service,
218
+ deviceObj.subservice,
219
+ deviceObj.type,
220
+ deviceObj.apikey,
221
+ handlerGroupFindByType
222
+ );
222
223
  }
223
224
 
224
225
  /**
@@ -353,12 +354,6 @@ function registerDevice(deviceObj, callback) {
353
354
  deviceObj.staticAttributes = deviceObj.staticAttributes ? deviceObj.staticAttributes : [];
354
355
  deviceObj.commands = deviceObj.commands ? deviceObj.commands : [];
355
356
  deviceObj.lazy = deviceObj.lazy ? deviceObj.lazy : [];
356
- if ('timestamp' in deviceData && deviceData.timestamp !== undefined) {
357
- deviceObj.timestamp = deviceData.timestamp;
358
- }
359
- if ('explicitAttrs' in deviceData && deviceData.explicitAttrs !== undefined) {
360
- deviceObj.explicitAttrs = deviceData.explicitAttrs;
361
- }
362
357
  if ('apikey' in deviceData && deviceData.apikey !== undefined) {
363
358
  deviceObj.apikey = deviceData.apikey;
364
359
  }
@@ -56,53 +56,6 @@ function jsonConcat(json1, json2) {
56
56
  }
57
57
  }
58
58
 
59
- /**
60
- * Creates the response handler for the initial entity creation request using NGSI-LD.
61
- * This handler basically deals with the errors that could have been rised during
62
- * the communication with the Context Broker.
63
- *
64
- * @param {Object} deviceData Object containing all the deviceData needed to send the registration.
65
- * @param {Object} newDevice Device object that will be stored in the database.
66
- * @return {function} Handler to pass to the request() function.
67
- */
68
- function createInitialEntityHandlerNgsiLD(deviceData, newDevice, callback) {
69
- return function handleInitialEntityResponse(error, response, body) {
70
- if (error) {
71
- logger.error(
72
- context,
73
- 'ORION-001: Connection error creating inital entity in the Context Broker: %s',
74
- error
75
- );
76
-
77
- alarms.raise(constants.ORION_ALARM, error);
78
-
79
- callback(error);
80
- }
81
- // Handling different response codes for batch entity upsert in NGSI-LD specification:
82
- // - In v1.2.1, response code is 200
83
- // - In v1.3.1, response code is 201 if some created entities, 204 if just updated existing
84
- else if (
85
- response &&
86
- (response.statusCode === 200 || response.statusCode === 201 || response.statusCode === 204)
87
- ) {
88
- alarms.release(constants.ORION_ALARM);
89
- logger.debug(context, 'Initial entity created successfully.');
90
- callback(null, newDevice);
91
- } else {
92
- logger.error(
93
- context,
94
- 'Protocol error connecting to the Context Broker [%d]: %s',
95
- response.statusCode,
96
- body
97
- );
98
-
99
- const errorObj = new errors.EntityGenericError(deviceData.id, deviceData.type, body);
100
-
101
- callback(errorObj);
102
- }
103
- };
104
- }
105
-
106
59
  /**
107
60
  * Creates the response handler for the update entity request using NGSI-LD.
108
61
  * This handler basically deals with the errors
@@ -154,54 +107,8 @@ function updateEntityHandlerNgsiLD(deviceData, updatedDevice, callback) {
154
107
  * @param {Object} deviceData Object containing all the deviceData needed to send the registration.
155
108
  * @param {Object} newDevice Device object that will be stored in the database.
156
109
  */
157
- function createInitialEntityNgsiLD(deviceData, newDevice, callback) {
158
- let json = {
159
- id: String(deviceData.name),
160
- type: deviceData.type
161
- };
162
-
163
- jsonConcat(json, NGSIv2.formatAttributes(deviceData.active, false));
164
- jsonConcat(json, NGSIv2.formatAttributes(deviceData.staticAttributes, true));
165
- jsonConcat(json, NGSIv2.formatCommands(deviceData.commands));
166
-
167
- if (
168
- ('timestamp' in deviceData && deviceData.timestamp !== undefined
169
- ? deviceData.timestamp
170
- : config.getConfig().timestamp) &&
171
- !utils.isTimestampedNgsi2(json)
172
- ) {
173
- logger.debug(context, 'config.timestamp %s %s', deviceData.timestamp, config.getConfig().timestamp);
174
-
175
- json[constants.TIMESTAMP_ATTRIBUTE] = {
176
- type: constants.TIMESTAMP_TYPE_NGSI2,
177
- value: moment()
178
- };
179
- }
180
-
181
- json = ngsiLD.formatAsNGSILD(json);
182
-
183
- const options = {
184
- url: config.getConfig().contextBroker.url + '/ngsi-ld/v1/entityOperations/upsert/',
185
- method: 'POST',
186
- json: [json],
187
- headers: {
188
- 'fiware-service': deviceData.service,
189
- 'fiware-servicepath': deviceData.subservice,
190
- 'NGSILD-Tenant': deviceData.service,
191
- 'NGSILD-Path': deviceData.subservice,
192
- 'Content-Type': 'application/ld+json'
193
- }
194
- };
195
-
196
- if (deviceData.cbHost && deviceData.cbHost.indexOf('://') !== -1) {
197
- options.url = deviceData.cbHost + '/ngsi-ld/v1/entityOperations/upsert/';
198
- } else if (deviceData.cbHost && deviceData.cbHost.indexOf('://') === -1) {
199
- options.url = 'http://' + deviceData.cbHost + '/ngsi-ld/v1/entityOperations/upsert/';
200
- }
201
-
202
- logger.debug(context, 'deviceData: %j', deviceData);
203
- logger.debug(context, 'Creating initial entity in the Context Broker:\n %s', JSON.stringify(options, null, 4));
204
- utils.executeWithSecurity(options, newDevice, createInitialEntityHandlerNgsiLD(deviceData, newDevice, callback));
110
+ function createInitialEntityNgsiLDFake(deviceData, newDevice, callback) {
111
+ callback(null, newDevice);
205
112
  }
206
113
 
207
114
  /**
@@ -281,9 +188,10 @@ function updateRegisterDeviceNgsiLD(deviceObj, entityInfoUpdated, callback) {
281
188
  return;
282
189
  }
283
190
 
284
- logger.debug(context, 'Update provisioned LD device in Device Service');
191
+ logger.debug(context, 'Update provisioned LD device in Device Service %j %j', deviceObj, entityInfoUpdated);
285
192
 
286
193
  function combineWithNewDevice(newDevice, oldDevice, callback) {
194
+ logger.debug(context, 'combineWithNewDevice %j %j', newDevice, oldDevice);
287
195
  if (oldDevice) {
288
196
  oldDevice.internalId = newDevice.internalId;
289
197
  oldDevice.lazy = newDevice.lazy;
@@ -377,7 +285,7 @@ function updateRegisterDeviceNgsiLD(deviceObj, entityInfoUpdated, callback) {
377
285
  deviceObj.subservice
378
286
  ),
379
287
  apply(extractDeviceDifference, deviceObj),
380
- createInitialEntityNgsiLD,
288
+ createInitialEntityNgsiLDFake,
381
289
  apply(combineWithNewDevice, deviceObj),
382
290
  apply(registrationUtils.sendRegistrations, false),
383
291
  apply(registrationUtils.processContextRegistration, deviceObj),
@@ -407,5 +315,4 @@ function updateRegisterDeviceNgsiLD(deviceObj, entityInfoUpdated, callback) {
407
315
  }
408
316
  }
409
317
 
410
- exports.createInitialEntity = createInitialEntityNgsiLD;
411
318
  exports.updateRegisterDevice = updateRegisterDeviceNgsiLD;
@@ -27,19 +27,6 @@ const config = require('../../commonConfig');
27
27
  const deviceHandlerLD = require('./devices-NGSI-LD');
28
28
  const deviceHandlerV2 = require('./devices-NGSI-v2');
29
29
 
30
- /**
31
- * Creates the initial entity representing the device in the Context Broker using both NGSI-LD and NGSI-v2
32
- * This is important mainly to allow the rest of the updateContext operations to be performed.
33
- *
34
- * @param {Object} deviceData Object containing all the deviceData needed to send the registration.
35
- * @param {Object} newDevice Device object that will be stored in the database.
36
- */
37
- function createInitialEntityNgsiMixed(deviceData, newDevice, callback) {
38
- if (config.checkNgsiLD(deviceData)) {
39
- deviceHandlerLD.createInitialEntity(deviceData, newDevice, callback);
40
- }
41
- }
42
-
43
30
  /**
44
31
  * Updates the register of an existing device identified by the Id and Type in the Context Broker, and the internal
45
32
  * registry. It uses both NGSI-LD and NGSI-v2
@@ -59,5 +46,4 @@ function updateRegisterDeviceNgsiMixed(deviceObj, entityInfoUpdated, callback) {
59
46
  }
60
47
  }
61
48
 
62
- exports.createInitialEntity = createInitialEntityNgsiMixed;
63
49
  exports.updateRegisterDevice = updateRegisterDeviceNgsiMixed;
@@ -270,6 +270,9 @@ function updateRegisterDeviceNgsi2(deviceObj, entityInfoUpdated, callback) {
270
270
  if ('apikey' in newDevice && newDevice.apikey !== undefined) {
271
271
  oldDevice.apikey = newDevice.apikey;
272
272
  }
273
+ if ('payloadType' in newDevice && newDevice.payloadType !== undefined) {
274
+ oldDevice.payloadType = newDevice.payloadType;
275
+ }
273
276
  oldDevice.endpoint = newDevice.endpoint || oldDevice.endpoint;
274
277
 
275
278
  callback(null, oldDevice);
@@ -27,7 +27,6 @@ let registeredGroups = {};
27
27
  const logger = require('logops');
28
28
  const intoTrans = require('../common/domain').intoTrans;
29
29
  const errors = require('../../errors');
30
- const config = require('../../commonConfig');
31
30
  const _ = require('underscore');
32
31
  const context = {
33
32
  op: 'IoTAgentNGSI.InMemoryGroupRegister'
@@ -131,31 +130,7 @@ function clear(callback) {
131
130
  callback();
132
131
  }
133
132
 
134
- function findSingleConfigurationMode(service, subservice, callback) {
135
- let result;
136
-
137
- for (const i in registeredGroups) {
138
- if (
139
- registeredGroups.hasOwnProperty(i) &&
140
- registeredGroups[i].service === service &&
141
- registeredGroups[i].subservice === subservice
142
- ) {
143
- result = registeredGroups[i];
144
- break;
145
- }
146
- }
147
-
148
- if (result) {
149
- callback(null, result);
150
- } else {
151
- callback(new errors.DeviceGroupNotFound(service, subservice));
152
- }
153
- }
154
-
155
133
  function find(service, subservice, callback) {
156
- if (config.getConfig().singleConfigurationMode === true) {
157
- return findSingleConfigurationMode(service, subservice, callback);
158
- }
159
134
  const result = [];
160
135
 
161
136
  for (const i in registeredGroups) {
@@ -58,7 +58,8 @@ const attributeList = [
58
58
  'expressionLanguage',
59
59
  'defaultEntityNameConjunction',
60
60
  'ngsiVersion',
61
- 'entityNameExp'
61
+ 'entityNameExp',
62
+ 'payloadType'
62
63
  ];
63
64
 
64
65
  /**
@@ -147,15 +148,15 @@ function listGroups(service, limit, offset, callback) {
147
148
  query.skip(parseInt(offset, 10));
148
149
  }
149
150
 
150
- async.series([query.exec.bind(query), Group.model.countDocuments.bind(Group.model, condition)], function (
151
- error,
152
- results
153
- ) {
154
- callback(error, {
155
- count: results[1],
156
- services: results[0].map(toObjectFn)
157
- });
158
- });
151
+ async.series(
152
+ [query.exec.bind(query), Group.model.countDocuments.bind(Group.model, condition)],
153
+ function (error, results) {
154
+ callback(error, {
155
+ count: results[1],
156
+ services: results[0].map(toObjectFn)
157
+ });
158
+ }
159
+ );
159
160
  }
160
161
 
161
162
  function getById(id, callback) {
@@ -201,15 +202,15 @@ function find(service, subservice, callback) {
201
202
 
202
203
  const query = Group.model.find(condition).sort();
203
204
 
204
- async.series([query.exec.bind(query), Group.model.countDocuments.bind(Group.model, condition)], function (
205
- error,
206
- results
207
- ) {
208
- callback(error, {
209
- count: results[1],
210
- services: results[0].map(toObjectFn)
211
- });
212
- });
205
+ async.series(
206
+ [query.exec.bind(query), Group.model.countDocuments.bind(Group.model, condition)],
207
+ function (error, results) {
208
+ callback(error, {
209
+ count: results[1],
210
+ services: results[0].map(toObjectFn)
211
+ });
212
+ }
213
+ );
213
214
  }
214
215
 
215
216
  function findOneInMongoDB(queryObj, fields, callback) {
@@ -59,10 +59,6 @@ function validateGroup(group, callback) {
59
59
  config.getGroupRegistry().getSilently(group.resource, group.apikey, generateDuplicateHandler(innerCb));
60
60
  }
61
61
 
62
- function checkServiceAndSubservice(innerCb) {
63
- config.getGroupRegistry().find(group.service, group.subservice, generateDuplicateHandler(innerCb));
64
- }
65
-
66
62
  function checkMandatoryParams(innerCb) {
67
63
  if (!group.service) {
68
64
  innerCb(new errors.MissingConfigParams(['service']));
@@ -74,22 +70,15 @@ function validateGroup(group, callback) {
74
70
  return;
75
71
  }
76
72
 
77
- if (config.getConfig().singleConfigurationMode === false) {
78
- if (!group.type) {
79
- innerCb(new errors.MissingConfigParams(['type']));
80
- return;
81
- }
73
+ if (!group.type) {
74
+ innerCb(new errors.MissingConfigParams(['type']));
75
+ return;
82
76
  }
83
77
 
84
78
  innerCb();
85
79
  }
86
80
 
87
81
  validations.push(checkApiKeyAndResource);
88
-
89
- if (config.getConfig().singleConfigurationMode === true) {
90
- validations.push(checkServiceAndSubservice);
91
- }
92
-
93
82
  validations.push(checkMandatoryParams);
94
83
 
95
84
  async.series(validations, callback);
@@ -41,11 +41,87 @@ const _ = require('underscore');
41
41
  const context = {
42
42
  op: 'IoTAgentNGSI-LD'
43
43
  };
44
- const NGSIv2 = require('./entities-NGSI-v2');
45
44
  const NGSIUtils = require('./ngsiUtils');
46
45
 
47
46
  const NGSI_LD_URN = 'urn:ngsi-ld:';
48
47
 
48
+ /**
49
+ * Adds timestamp to ngsi payload entities accoding to timezone, and an optional timestampvalue.
50
+ *
51
+ * @param {Object} payload NGSIv2 payload with one or more entities
52
+ * @param String timezone TimeZone value (optional)
53
+ * @param String timestampValue Timestamp value (optional). If not provided current timestamp is used
54
+ * @param Boolean skipMetadataAtt An optional flag to indicate if timestamp should be added to each metadata attribute. Default is false
55
+ * @return {Object} NGSIv2 payload entities with timestamp
56
+ */
57
+ function addTimestamp(payload, timezone, timestampValue) {
58
+ function addTimestampEntity(entity, timezone, timestampValue) {
59
+ const timestamp = {
60
+ type: constants.TIMESTAMP_TYPE_NGSI2
61
+ };
62
+
63
+ if (timestampValue) {
64
+ timestamp.value = timestampValue;
65
+ } else if (!timezone) {
66
+ timestamp.value = new Date().toISOString();
67
+ } else {
68
+ timestamp.value = moment().tz(timezone).format('YYYY-MM-DD[T]HH:mm:ss.SSSZ');
69
+ }
70
+
71
+ function addMetadata(attribute) {
72
+ let timestampFound = false;
73
+
74
+ if (!attribute.metadata) {
75
+ attribute.metadata = {};
76
+ }
77
+
78
+ for (let i = 0; i < attribute.metadata.length; i++) {
79
+ if (attribute.metadata[i] === constants.TIMESTAMP_ATTRIBUTE) {
80
+ if (
81
+ attribute.metadata[constants.TIMESTAMP_ATTRIBUTE].type === constants.TIMESTAMP_TYPE_NGSI2 &&
82
+ attribute.metadata[constants.TIMESTAMP_ATTRIBUTE].value === timestamp.value
83
+ ) {
84
+ timestampFound = true;
85
+ break;
86
+ }
87
+ }
88
+ }
89
+
90
+ if (!timestampFound) {
91
+ attribute.metadata[constants.TIMESTAMP_ATTRIBUTE] = timestamp;
92
+ }
93
+
94
+ return attribute;
95
+ }
96
+ let keyCount = 0;
97
+ for (const key in entity) {
98
+ /* eslint-disable-next-line no-prototype-builtins */
99
+ if (entity.hasOwnProperty(key) && key !== 'id' && key !== 'type') {
100
+ addMetadata(entity[key]);
101
+ keyCount += 1;
102
+ }
103
+ }
104
+ // Add timestamp just to entity with attrs: multientity plugin could
105
+ // create empty entities just with id and type.
106
+ if (keyCount > 0) {
107
+ entity[constants.TIMESTAMP_ATTRIBUTE] = timestamp;
108
+ }
109
+
110
+ return entity;
111
+ }
112
+
113
+ if (payload instanceof Array) {
114
+ for (let i = 0; i < payload.length; i++) {
115
+ if (!utils.isTimestampedNgsi2(payload[i])) {
116
+ payload[i] = addTimestampEntity(payload[i], timezone, timestampValue);
117
+ }
118
+ }
119
+
120
+ return payload;
121
+ }
122
+ return addTimestampEntity(payload, timezone, timestampValue);
123
+ }
124
+
49
125
  /**
50
126
  * Amends an NGSIv2 attribute to NGSI-LD format
51
127
  * All native JSON types are respected and cast as Property values
@@ -843,7 +919,7 @@ function sendUpdateValueNgsiLD(entityName, attributes, typeInformation, token, c
843
919
  ? config.getConfig().timestamp
844
920
  : timestampValue !== undefined
845
921
  ) {
846
- newEntity = NGSIv2.addTimestamp(newEntity, typeInformation.timezone, timestampValue);
922
+ newEntity = addTimestamp(newEntity, typeInformation.timezone, timestampValue);
847
923
  logger.debug(context, 'sendUpdateValueNgsiLD \n timestamped newEntity=%j', newEntity);
848
924
  }
849
925
  payload.push(newEntity);
@@ -927,14 +1003,14 @@ function sendUpdateValueNgsiLD(entityName, attributes, typeInformation, token, c
927
1003
  // timeInstant is provided as measure
928
1004
  if (Object.keys(payload[0]).length > 1) {
929
1005
  // include metadata with TimeInstant in attrs when TimeInstant is provided as measure in all entities
930
- payload[0] = NGSIv2.addTimestamp(payload[0], typeInformation.timezone, timestampValue);
1006
+ payload[0] = addTimestamp(payload[0], typeInformation.timezone, timestampValue);
931
1007
  }
932
1008
  } else {
933
1009
  // jshint maxdepth:5
934
1010
  for (let n = 0; n < payload.length; n++) {
935
1011
  if (!utils.isTimestampedNgsi2(payload[n])) {
936
1012
  // legacy check needed?
937
- payload[n] = NGSIv2.addTimestamp(payload[n], typeInformation.timezone);
1013
+ payload[n] = addTimestamp(payload[n], typeInformation.timezone);
938
1014
  // jshint maxdepth:5
939
1015
  } else if (!utils.IsValidTimestampedNgsi2(payload[n])) {
940
1016
  // legacy check needed?
@@ -955,9 +1031,8 @@ function sendUpdateValueNgsiLD(entityName, attributes, typeInformation, token, c
955
1031
  delete payload[m][key].object_id;
956
1032
  }
957
1033
  }
958
- payload[m] = NGSIUtils.castJsonNativeAttributes(payload[m]); // native types
959
1034
  }
960
- logger.debug(context, 'sendUpdateValueNgsiLD \n payload with native types and without object_id %j', payload);
1035
+ logger.debug(context, 'sendUpdateValueNgsiLD \n payload and without object_id %j', payload);
961
1036
 
962
1037
  options.json = payload;
963
1038
  try {