iotagent-node-lib 4.2.0 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -89,7 +89,13 @@ function updateEntityHandlerNgsi2(deviceData, updatedDevice, callback) {
89
89
  body
90
90
  );
91
91
 
92
- const errorObj = new errors.EntityGenericError(deviceData.id, deviceData.type, body, response.statusCode);
92
+ const errorObj = new errors.EntityGenericError(
93
+ deviceData.id,
94
+ deviceData.type,
95
+ deviceData,
96
+ body,
97
+ response.statusCode
98
+ );
93
99
 
94
100
  callback(errorObj);
95
101
  }
@@ -204,7 +210,7 @@ function updateEntityNgsi2(deviceData, updatedDevice, callback) {
204
210
  // Format any GeoJSON attrs properly
205
211
  options.json[att] = NGSIv2.formatGeoAttrs(options.json[att]);
206
212
  } catch (error) {
207
- return callback(new errors.BadGeocoordinates(JSON.stringify(options.json)));
213
+ return callback(new errors.BadGeocoordinates(JSON.stringify(options.json), deviceData));
208
214
  }
209
215
  }
210
216
 
@@ -243,7 +249,7 @@ function updateEntityNgsi2(deviceData, updatedDevice, callback) {
243
249
  */
244
250
  function updateRegisterDeviceNgsi2(deviceObj, entityInfoUpdated, callback) {
245
251
  if (!deviceObj.id || !deviceObj.type) {
246
- callback(new errors.MissingAttributes('Id or device missing'));
252
+ callback(new errors.MissingAttributes('Id or device missing', deviceObj));
247
253
  return;
248
254
  }
249
255
 
@@ -282,7 +288,7 @@ function updateRegisterDeviceNgsi2(deviceObj, entityInfoUpdated, callback) {
282
288
 
283
289
  callback(null, oldDevice);
284
290
  } else {
285
- callback(new errors.DeviceNotFound(newDevice.id));
291
+ callback(new errors.DeviceNotFound(newDevice.id, newDevice));
286
292
  }
287
293
  }
288
294
 
@@ -50,7 +50,7 @@ function exists(group) {
50
50
 
51
51
  function createGroup(group, callback) {
52
52
  if (exists(group)) {
53
- callback(new errors.DuplicateGroup(group.resource, group.apikey));
53
+ callback(new errors.DuplicateGroup(group));
54
54
  } else {
55
55
  const storeGroup = _.clone(group);
56
56
 
@@ -110,7 +110,7 @@ function createGroup(group, callback) {
110
110
  group.apikey
111
111
  );
112
112
 
113
- callback(new errors.DuplicateGroup(group.resource, group.apikey));
113
+ callback(new errors.DuplicateGroup(group));
114
114
  } else {
115
115
  logger.debug(context, 'Error storing device group information: %s', error);
116
116
 
@@ -48,7 +48,7 @@ function validateGroup(group, callback) {
48
48
  return function (error, foundGroup) {
49
49
  logger.debug(context, 'generateDuplicateHander error %j and foundGroup %j', error, foundGroup);
50
50
  if (!error || (foundGroup && foundGroup.count > 0)) {
51
- innerCb(new errors.DuplicateGroup(group.resource, group.apikey));
51
+ innerCb(new errors.DuplicateGroup(group));
52
52
  } else {
53
53
  innerCb();
54
54
  }
@@ -291,8 +291,14 @@ function getEffectiveApiKey(service, subservice, type, callback) {
291
291
  logger.debug(context, 'Using default API Key: %s', config.getConfig().defaultKey);
292
292
  callback(null, config.getConfig().defaultKey);
293
293
  } else {
294
- logger.error(context, 'Could not find any API Key information for device.');
295
- callback(new errors.GroupNotFound(service, subservice));
294
+ logger.error(
295
+ context,
296
+ 'Could not find any APIKey information for device in service %s subservice %s and type %s',
297
+ service,
298
+ subservice,
299
+ type
300
+ );
301
+ callback(new errors.GroupNotFound(service, subservice, type));
296
302
  }
297
303
  }
298
304
 
@@ -381,9 +381,9 @@ function generateNGSILDOperationHandler(operationName, entityName, typeInformati
381
381
  }
382
382
 
383
383
  if (errorField !== undefined) {
384
- callback(new errors.DeviceNotFound(entityName));
384
+ callback(new errors.DeviceNotFound(entityName, typeInformation));
385
385
  } else {
386
- callback(new errors.EntityGenericError(entityName, typeInformation.type, body));
386
+ callback(new errors.EntityGenericError(entityName, typeInformation.type, typeInformation, body));
387
387
  }
388
388
  } else {
389
389
  logger.debug(context, 'Unknown error executing ' + operationName + ' operation');
@@ -391,7 +391,15 @@ function generateNGSILDOperationHandler(operationName, entityName, typeInformati
391
391
  body = JSON.parse(body);
392
392
  }
393
393
 
394
- callback(new errors.EntityGenericError(entityName, typeInformation.type, body, response.statusCode));
394
+ callback(
395
+ new errors.EntityGenericError(
396
+ entityName,
397
+ typeInformation.type,
398
+ typeInformation,
399
+ body,
400
+ response.statusCode
401
+ )
402
+ );
395
403
  }
396
404
  };
397
405
  }
@@ -416,7 +424,7 @@ function sendQueryValueNgsiLD(entityName, attributes, typeInformation, token, ca
416
424
  options.method = 'GET';
417
425
 
418
426
  if (!typeInformation || !typeInformation.type) {
419
- callback(new errors.TypeNotFound(null, entityName));
427
+ callback(new errors.TypeNotFound(null, entityName, typeInformation));
420
428
  return;
421
429
  }
422
430
 
@@ -529,7 +537,7 @@ function sendUpdateValueNgsiLD(entityName, attributes, typeInformation, token, c
529
537
  }
530
538
 
531
539
  if (!typeInformation || !typeInformation.type) {
532
- callback(new errors.TypeNotFound(null, entityName));
540
+ callback(new errors.TypeNotFound(null, entityName, typeInformation));
533
541
  return;
534
542
  }
535
543
  const idTypeSSSList = pluginUtils.getIdTypeServSubServiceFromDevice(typeInformation);
@@ -1015,7 +1023,7 @@ function sendUpdateValueNgsiLD(entityName, attributes, typeInformation, token, c
1015
1023
  } else if (!utils.IsValidTimestampedNgsi2(payload[n])) {
1016
1024
  // legacy check needed?
1017
1025
  logger.error(context, 'Invalid timestamp:%s', JSON.stringify(payload[0]));
1018
- callback(new errors.BadTimestamp(payload, entityName));
1026
+ callback(new errors.BadTimestamp(payload, entityName, typeInformation));
1019
1027
  return;
1020
1028
  }
1021
1029
  }
@@ -1044,7 +1052,7 @@ function sendUpdateValueNgsiLD(entityName, attributes, typeInformation, token, c
1044
1052
  options.json = [formatAsNGSILD(options.json)];
1045
1053
  }
1046
1054
  } catch (error) {
1047
- return callback(new errors.BadGeocoordinates(JSON.stringify(payload)));
1055
+ return callback(new errors.BadGeocoordinates(JSON.stringify(payload), typeInformation));
1048
1056
  }
1049
1057
 
1050
1058
  if (typeInformation.active) {
@@ -31,7 +31,6 @@ const request = require('../../request-shim');
31
31
  const alarms = require('../common/alarmManagement');
32
32
  const errors = require('../../errors');
33
33
  const pluginUtils = require('../../plugins/pluginUtils');
34
- const config = require('../../commonConfig');
35
34
  const constants = require('../../constants');
36
35
  const jexlParser = require('../../plugins/jexlParser');
37
36
  const expressionPlugin = require('../../plugins/expressionPlugin');
@@ -173,9 +172,9 @@ function generateNGSI2OperationHandler(operationName, entityName, typeInformatio
173
172
  }
174
173
 
175
174
  if (errorField !== undefined) {
176
- callback(new errors.DeviceNotFound(entityName));
175
+ callback(new errors.DeviceNotFound(entityName, typeInformation));
177
176
  } else {
178
- callback(new errors.EntityGenericError(entityName, typeInformation.type, body));
177
+ callback(new errors.EntityGenericError(entityName, typeInformation.type, typeInformation, body));
179
178
  }
180
179
  } else {
181
180
  logger.debug(context, 'Unknown error executing ' + operationName + ' operation');
@@ -183,7 +182,15 @@ function generateNGSI2OperationHandler(operationName, entityName, typeInformatio
183
182
  body = JSON.parse(body);
184
183
  }
185
184
 
186
- callback(new errors.EntityGenericError(entityName, typeInformation.type, body, response.statusCode));
185
+ callback(
186
+ new errors.EntityGenericError(
187
+ entityName,
188
+ typeInformation.type,
189
+ typeInformation,
190
+ body,
191
+ response.statusCode
192
+ )
193
+ );
187
194
  }
188
195
  };
189
196
  }
@@ -225,7 +232,7 @@ function sendQueryValueNgsi2(entityName, attributes, typeInformation, token, cal
225
232
  options.method = 'GET';
226
233
 
227
234
  if (!typeInformation || !typeInformation.type) {
228
- callback(new errors.TypeNotFound(null, entityName));
235
+ callback(new errors.TypeNotFound(null, entityName, typeInformation));
229
236
  return;
230
237
  }
231
238
 
@@ -279,7 +286,7 @@ function sendUpdateValueNgsi2(entityName, measures, typeInformation, token, call
279
286
 
280
287
  //Check mandatory information: type
281
288
  if (!typeInformation || !typeInformation.type) {
282
- callback(new errors.TypeNotFound(null, entityName));
289
+ callback(new errors.TypeNotFound(null, entityName, typeInformation));
283
290
  return;
284
291
  }
285
292
  //Rename all measures with matches with id and type to measure_id and measure_type
@@ -301,11 +308,9 @@ function sendUpdateValueNgsi2(entityName, measures, typeInformation, token, call
301
308
  jexlctxt = reduceAttrToPlainObject(idTypeSSSList, jexlctxt);
302
309
 
303
310
  //Managing timestamp (mustInsertTimeInstant flag to decide if we should insert Timestamp later on)
304
- const mustInsertTimeInstant =
305
- typeInformation.timestamp !== undefined
306
- ? typeInformation.timestamp
307
- : config.getConfig().timestamp !== undefined
308
- ? config.getConfig().timestamp
311
+ const mustInsertTimeInstant =
312
+ typeInformation.timestamp !== undefined
313
+ ? typeInformation.timestamp
309
314
  : false;
310
315
 
311
316
  if (mustInsertTimeInstant) {
@@ -317,7 +322,10 @@ function sendUpdateValueNgsi2(entityName, measures, typeInformation, token, call
317
322
  if (moment(plainMeasures[constants.TIMESTAMP_ATTRIBUTE], moment.ISO_8601, true).isValid()) {
318
323
  timestamp.value = plainMeasures[constants.TIMESTAMP_ATTRIBUTE];
319
324
  } else {
320
- callback(new errors.BadTimestamp(plainMeasures[constants.TIMESTAMP_ATTRIBUTE], entityName));
325
+ callback(
326
+ new errors.BadTimestamp(plainMeasures[constants.TIMESTAMP_ATTRIBUTE], entityName, typeInformation)
327
+ );
328
+ return;
321
329
  }
322
330
  } else if (!typeInformation.timezone) {
323
331
  timestamp.value = new Date().toISOString();
@@ -144,9 +144,9 @@ function executeWithDeviceInformation(operationFunction) {
144
144
  // For preregistered devices, augment the existing deviceInformation with selected attributes.
145
145
  if (!callback) {
146
146
  callback = deviceInformation;
147
- typeInformation = deviceGroup || configDeviceInfo;
147
+ typeInformation = deviceGroup || { ...config.getConfig(), ...configDeviceInfo };
148
148
  } else {
149
- typeInformation = deviceInformation;
149
+ typeInformation = { ...config.getConfig(), ...deviceInformation };
150
150
  attributeList.forEach((key) => {
151
151
  typeInformation[key] =
152
152
  typeInformation[key] || (deviceGroup || {})[key] || (configDeviceInfo || {})[key];
@@ -236,7 +236,7 @@ function setCommandResult(
236
236
  if (commandInfo.length === 1) {
237
237
  exports.update(entityName, typeInformation.type, apikey, attributes, typeInformation, callback);
238
238
  } else {
239
- callback(new errors.CommandNotFound(commandName));
239
+ callback(new errors.CommandNotFound(commandName, typeInformation));
240
240
  }
241
241
  });
242
242
  }
@@ -62,6 +62,7 @@ function createSubscriptionHandlerNgsiLD(device, triggers, store, callback) {
62
62
  new errors.EntityGenericError(
63
63
  device.name,
64
64
  device.type,
65
+ device,
65
66
  {
66
67
  details: body
67
68
  },
@@ -183,6 +184,7 @@ function createUnsubscribeHandlerNgsiLD(device, id, callback) {
183
184
  new errors.EntityGenericError(
184
185
  device.name,
185
186
  device.type,
187
+ device,
186
188
  {
187
189
  details: body
188
190
  },
@@ -64,6 +64,7 @@ function createSubscriptionHandlerNgsi2(device, triggers, store, callback) {
64
64
  new errors.EntityGenericError(
65
65
  device.name,
66
66
  device.type,
67
+ device,
67
68
  {
68
69
  details: body
69
70
  },
@@ -183,6 +184,7 @@ function createUnsubscribeHandlerNgsi2(device, id, callback) {
183
184
  new errors.EntityGenericError(
184
185
  device.name,
185
186
  device.type,
187
+ device,
186
188
  {
187
189
  details: body
188
190
  },
@@ -48,41 +48,36 @@ const overwritePaths = ['/ngsi-ld/v1/entities/:entity/attrs', '/ngsi-ld/v1/entit
48
48
  const updatePaths = ['/ngsi-ld/v1/entities/:entity/attrs', '/ngsi-ld/v1/entities/:entity/attrs/:attr'];
49
49
  const queryPaths = ['/ngsi-ld/v1/entities/:entity'];
50
50
 
51
-
52
51
  /**
53
52
  * Replacement of NGSI-LD Null placeholders with real null values
54
53
  *
55
54
  */
56
- function replaceNGSILDNull(payload){
57
- Object.keys(payload).forEach((key) =>{
55
+ function replaceNGSILDNull(payload) {
56
+ Object.keys(payload).forEach((key) => {
58
57
  const value = payload[key];
59
- if ( value === constants.NGSI_LD_NULL){
60
- payload[key] = null;
61
- } else if (typeof value === 'object' &&
62
- !Array.isArray(value) &&
63
- value !== null){
58
+ if (value === constants.NGSI_LD_NULL) {
59
+ payload[key] = null;
60
+ } else if (typeof value === 'object' && !Array.isArray(value) && value !== null) {
64
61
  payload[key] = replaceNGSILDNull(payload[key]);
65
62
  }
66
- })
67
- return payload;
63
+ });
64
+ return payload;
68
65
  }
69
66
 
70
67
  /**
71
68
  * Check to see if the payload or its subattributes contain null values
72
69
  *
73
70
  */
74
- function containsNulls(payload, result){
75
- Object.keys(payload).forEach((key) =>{
71
+ function containsNulls(payload, result) {
72
+ Object.keys(payload).forEach((key) => {
76
73
  const value = payload[key];
77
- if ( value === null){
78
- result.nulls = true;
79
- } else if (typeof value === 'object' &&
80
- !Array.isArray(value) &&
81
- value !== null){
74
+ if (value === null) {
75
+ result.nulls = true;
76
+ } else if (typeof value === 'object' && !Array.isArray(value) && value !== null) {
82
77
  containsNulls(payload[key], result);
83
78
  }
84
- })
85
- return result;
79
+ });
80
+ return result;
86
81
  }
87
82
 
88
83
  /**
@@ -90,23 +85,23 @@ function containsNulls(payload, result){
90
85
  * to real nulls and checks for the presence of null and datasetId
91
86
  *
92
87
  */
93
- function preprocessNGSILD(req, res, next){
94
- res.locals.hasDatasetId = false;
95
- const payload = req.body
96
- if (payload && typeof payload === 'object'){
97
- Object.keys(payload).forEach((key) =>{
98
- if (_.isArray(payload[key])){
88
+ function preprocessNGSILD(req, res, next) {
89
+ res.locals.hasDatasetId = false;
90
+ const payload = req.body;
91
+ if (payload && typeof payload === 'object') {
92
+ Object.keys(payload).forEach((key) => {
93
+ if (_.isArray(payload[key])) {
99
94
  payload[key].forEach((obj) => {
100
- if (obj.datasetId){
95
+ if (obj.datasetId) {
101
96
  res.locals.hasDatasetId = true;
102
97
  }
103
98
  });
104
- } else if (payload[key] && payload[key].datasetId && payload[key].datasetId !== '@none'){
105
- res.locals.hasDatasetId = true;
106
- }
99
+ } else if (payload[key] && payload[key].datasetId && payload[key].datasetId !== '@none') {
100
+ res.locals.hasDatasetId = true;
101
+ }
107
102
  });
108
103
  req.body = replaceNGSILDNull(payload);
109
- const result = { nulls: false }
104
+ const result = { nulls: false };
110
105
  containsNulls(payload, result);
111
106
  res.locals.hasNulls = result.nulls;
112
107
  }
@@ -124,16 +119,23 @@ function preprocessNGSILD(req, res, next){
124
119
  function validateNGSILD(supportNull, supportDatasetId) {
125
120
  return function validate(req, res, next) {
126
121
  if (!supportNull && res.locals.hasNulls) {
127
- next(new errors.BadRequest('NGSI-LD Null found within the payload. This IoT Agent does not support nulls for this endpoint.'));
122
+ next(
123
+ new errors.BadRequest(
124
+ 'NGSI-LD Null found within the payload. This IoT Agent does not support nulls for this endpoint.'
125
+ )
126
+ );
128
127
  } else if (!supportDatasetId && res.locals.hasDatasetId) {
129
- next(new errors.BadRequest('datasetId found within the payload. This IoT Agent does not support multi-attribute requests.'));
128
+ next(
129
+ new errors.BadRequest(
130
+ 'datasetId found within the payload. This IoT Agent does not support multi-attribute requests.'
131
+ )
132
+ );
130
133
  } else {
131
134
  next();
132
135
  }
133
136
  };
134
137
  }
135
138
 
136
-
137
139
  /**
138
140
  * Extract metadata attributes from input.
139
141
  *
@@ -413,34 +415,31 @@ function defaultQueryHandlerNgsiLD(id, type, service, subservice, attributes, ca
413
415
  * @param {Object} req Update request to generate Actions from
414
416
  */
415
417
  function generateMergePatchActionNgsiLD(req, callback) {
416
-
417
418
  const entityId = req.params.entity;
418
419
 
419
-
420
- function addAttributes(deviceData, body, attributes){
420
+ function addAttributes(deviceData, body, attributes) {
421
421
  const keys = Object.keys(body);
422
422
 
423
423
  for (const j in deviceData) {
424
424
  if (keys.includes(deviceData[j].name)) {
425
- const obj = body[deviceData[j].name]
426
- if ( obj === null) {
425
+ const obj = body[deviceData[j].name];
426
+ if (obj === null) {
427
427
  attributes.push({
428
428
  type: deviceData[j].type,
429
429
  value: null,
430
430
  name: deviceData[j].name
431
431
  });
432
432
  } else {
433
- attributes.push({
433
+ attributes.push({
434
434
  type: deviceData[j].type,
435
435
  value: obj.value,
436
436
  name: deviceData[j].name
437
437
  });
438
438
  }
439
- }
439
+ }
440
440
  }
441
441
  return attributes;
442
442
  }
443
-
444
443
 
445
444
  deviceService.getDeviceByName(
446
445
  entityId,
@@ -451,8 +450,8 @@ function generateMergePatchActionNgsiLD(req, callback) {
451
450
  callback(error);
452
451
  } else {
453
452
  const attributes = [];
454
- addAttributes(deviceObj.commands, req.body, attributes)
455
- addAttributes(deviceObj.lazy, req.body, attributes)
453
+ addAttributes(deviceObj.commands, req.body, attributes);
454
+ addAttributes(deviceObj.lazy, req.body, attributes);
456
455
  const executeMergePatchHandler = apply(
457
456
  contextServerUtils.mergePatchHandler,
458
457
  entityId,
@@ -461,10 +460,7 @@ function generateMergePatchActionNgsiLD(req, callback) {
461
460
  contextServerUtils.getLDPath(req),
462
461
  attributes
463
462
  );
464
- async.waterfall(
465
- [executeMergePatchHandler],
466
- callback()
467
- );
463
+ async.waterfall([executeMergePatchHandler], callback());
468
464
  }
469
465
  }
470
466
  );
@@ -477,7 +473,6 @@ function generateMergePatchActionNgsiLD(req, callback) {
477
473
  * @param {Object} res Response that will be sent.
478
474
  */
479
475
  function handleMergePatchNgsiLD(req, res, next) {
480
-
481
476
  function handleMergePatchRequest(error, result) {
482
477
  if (error) {
483
478
  logger.debug(context, 'There was an error handling the merge-patch: %s.', error);
@@ -492,15 +487,15 @@ function handleMergePatchNgsiLD(req, res, next) {
492
487
  if ((req.is('json') || req.is('application/ld+json')) === false) {
493
488
  return handleMergePatchRequest(new errors.UnsupportedContentType(req.header('content-type')));
494
489
  }
495
-
490
+
496
491
  if (req.body) {
497
492
  logger.debug(context, JSON.stringify(req.body, null, 4));
498
493
  }
499
494
 
500
- if (contextServerUtils.mergePatchHandler){
495
+ if (contextServerUtils.mergePatchHandler) {
501
496
  generateMergePatchActionNgsiLD(req, handleMergePatchRequest);
502
497
  } else {
503
- return handleMergePatchRequest(new errors.MethodNotSupported(req.method, req.path))
498
+ return handleMergePatchRequest(new errors.MethodNotSupported(req.method, req.path));
504
499
  }
505
500
  }
506
501
 
@@ -610,7 +605,7 @@ function handleQueryNgsiLD(req, res, next) {
610
605
  getFunction(function handleFindDevice(error, innerDevice) {
611
606
  let deviceList = [];
612
607
  if (!innerDevice) {
613
- return callback(new errors.DeviceNotFound(contextEntity.id));
608
+ return callback(new errors.DeviceNotFound(contextEntity.id, contextEntity));
614
609
  }
615
610
 
616
611
  if (innerDevice.count) {
@@ -689,7 +684,7 @@ function ErrorHandlingNgsiLD(action) {
689
684
  error: error.name,
690
685
  description: error.message.replace(/[<>\"\'=;\(\)]/g, '')
691
686
  });
692
- }
687
+ };
693
688
  }
694
689
 
695
690
  /**
@@ -812,7 +807,7 @@ function loadUnsupportedEndpointsNGSILD(router) {
812
807
  function loadContextRoutesNGSILD(router) {
813
808
  // In a more evolved implementation, more endpoints could be added to queryPathsNgsi2
814
809
  // according to https://www.etsi.org/standards-search#page=1&search=GS%20CIM%20009
815
-
810
+
816
811
  const support = config.getConfig().server.ldSupport;
817
812
  let i;
818
813
 
@@ -832,7 +827,7 @@ function loadContextRoutesNGSILD(router) {
832
827
  router.patch('/ngsi-ld/v1/entities/:entity', [
833
828
  preprocessNGSILD,
834
829
  validateNGSILD(support.null, support.datasetId),
835
- handleMergePatchNgsiLD,
830
+ handleMergePatchNgsiLD,
836
831
  ErrorHandlingNgsiLD('Merge-Patch')
837
832
  ]);
838
833
 
@@ -503,7 +503,7 @@ function handleQueryNgsi2(req, res, next) {
503
503
  getFunction(function handleFindDevice(error, innerDevice) {
504
504
  let deviceList = [];
505
505
  if (!innerDevice) {
506
- return callback(new errors.DeviceNotFound(contextEntity.id));
506
+ return callback(new errors.DeviceNotFound(contextEntity.id), contextEntity);
507
507
  }
508
508
 
509
509
  if (innerDevice.count) {