iotagent-node-lib 2.18.0 → 2.19.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.
- package/.github/workflows/ci.yml +1 -2
- package/doc/advanced-topics.md +122 -53
- package/doc/api.md +52 -52
- package/doc/development.md +8 -9
- package/doc/expressionLanguage.md +514 -316
- package/doc/installationguide.md +66 -64
- package/doc/usermanual.md +48 -16
- package/docker/Mosquitto/Dockerfile +1 -0
- package/docker/Mosquitto/README.md +1 -0
- package/docker/Mosquitto/startMosquitto.sh +6 -4
- package/lib/command/commandLine.js +1 -1
- package/lib/fiware-iotagent-lib.js +3 -0
- package/lib/jexlTranformsMap.js +9 -1
- package/lib/model/Device.js +4 -1
- package/lib/model/Group.js +19 -1
- package/lib/plugins/expressionParser.js +6 -4
- package/lib/plugins/expressionPlugin.js +8 -1
- package/lib/plugins/jexlParser.js +3 -1
- package/lib/request-shim.js +111 -0
- package/lib/services/common/genericMiddleware.js +6 -2
- package/lib/services/common/iotManagerService.js +1 -1
- package/lib/services/common/securityServiceKeystone.js +1 -1
- package/lib/services/common/securityServiceOAuth2.js +3 -2
- package/lib/services/devices/deviceRegistryMongoDB.js +1 -0
- package/lib/services/devices/devices-NGSI-LD.js +1 -1
- package/lib/services/devices/devices-NGSI-v2.js +2 -6
- package/lib/services/devices/registrationUtils.js +0 -2
- package/lib/services/ngsi/entities-NGSI-LD.js +95 -11
- package/lib/services/ngsi/entities-NGSI-v2.js +93 -8
- package/lib/services/ngsi/ngsiService.js +3 -2
- package/lib/services/northBound/contextServer-NGSI-LD.js +3 -2
- package/lib/services/northBound/deviceProvisioningServer.js +29 -6
- package/lib/services/northBound/northboundServer.js +2 -0
- package/lib/services/northBound/restUtils.js +1 -1
- package/package.json +4 -4
- package/test/tools/utils.js +2 -0
- package/test/unit/expressions/jexlExpression-test.js +5 -5
- package/test/unit/general/contextBrokerKeystoneSecurityAccess-test.js +1 -1
- package/test/unit/general/deviceService-test.js +2 -5
- package/test/unit/general/loglevel-api_test.js +6 -11
- package/test/unit/general/migration-test.js +1 -0
- package/test/unit/general/startup-test.js +1 -0
- package/test/unit/memoryRegistry/deviceRegistryMemory_test.js +1 -0
- package/test/unit/mongodb/mongodb-group-registry-test.js +1 -1
- package/test/unit/mongodb/mongodb-registry-test.js +2 -1
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin12a.json +7 -0
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin13.json +13 -13
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin1a.json +18 -0
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin29.json +18 -0
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin31.json +15 -0
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin32.json +17 -0
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin33.json +18 -0
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin34.json +17 -0
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin4a.json +36 -0
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin7.json +16 -16
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin8a.json +18 -0
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin15.json +25 -0
- package/test/unit/ngsi-ld/expressions/jexlBasedTransformations-test.js +1018 -0
- package/test/unit/ngsi-ld/general/contextBrokerOAuthSecurityAccess-test.js +2 -2
- package/test/unit/ngsi-ld/general/deviceService-test.js +1 -1
- package/test/unit/ngsi-ld/general/https-support-test.js +2 -1
- package/test/unit/ngsi-ld/general/iotam-autoregistration-test.js +2 -1
- package/test/unit/ngsi-ld/general/startup-test.js +1 -0
- package/test/unit/ngsi-ld/lazyAndCommands/active-devices-attribute-update-test.js +3 -1
- package/test/unit/ngsi-ld/lazyAndCommands/command-test.js +2 -1
- package/test/unit/ngsi-ld/lazyAndCommands/lazy-devices-test.js +2 -6
- package/test/unit/ngsi-ld/lazyAndCommands/polling-commands-test.js +2 -1
- package/test/unit/ngsi-ld/ngsiService/active-devices-test.js +1 -0
- package/test/unit/ngsi-ld/ngsiService/autocast-test.js +1 -0
- package/test/unit/ngsi-ld/ngsiService/geoproperties-test.js +1 -0
- package/test/unit/ngsi-ld/ngsiService/subscriptions-test.js +4 -3
- package/test/unit/ngsi-ld/plugins/alias-plugin_test.js +1 -0
- package/test/unit/ngsi-ld/plugins/bidirectional-plugin_test.js +3 -2
- package/test/unit/ngsi-ld/plugins/multientity-plugin_test.js +61 -0
- package/test/unit/ngsi-ld/provisioning/device-provisioning-api_test.js +2 -1
- package/test/unit/ngsi-ld/provisioning/device-registration_test.js +3 -2
- package/test/unit/ngsi-ld/provisioning/device-update-registration_test.js +1 -0
- package/test/unit/ngsi-ld/provisioning/listProvisionedDevices-test.js +42 -54
- package/test/unit/ngsi-ld/provisioning/provisionDeviceMultientity-test.js +2 -1
- package/test/unit/ngsi-ld/provisioning/removeProvisionedDevice-test.js +4 -4
- package/test/unit/ngsi-ld/provisioning/singleConfigurationMode-test.js +3 -5
- package/test/unit/ngsi-ld/provisioning/updateProvisionedDevices-test.js +12 -18
- package/test/unit/ngsi-mixed/provisioning/ngsi-versioning-test.js +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin17.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin32.json +16 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin33.json +22 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin34.json +12 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin15.json +25 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin16.json +25 -0
- package/test/unit/ngsiv2/expressions/expressionBasedTransformations-test.js +4 -4
- package/test/unit/ngsiv2/expressions/jexlBasedTransformations-test.js +500 -0
- package/test/unit/ngsiv2/general/contextBrokerOAuthSecurityAccess-test.js +3 -2
- package/test/unit/ngsiv2/general/deviceService-test.js +9 -8
- package/test/unit/ngsiv2/general/https-support-test.js +2 -1
- package/test/unit/ngsiv2/general/iotam-autoregistration-test.js +2 -1
- package/test/unit/ngsiv2/general/startup-test.js +1 -0
- package/test/unit/ngsiv2/lazyAndCommands/active-devices-attribute-update-test.js +3 -1
- package/test/unit/ngsiv2/lazyAndCommands/command-test.js +2 -1
- package/test/unit/ngsiv2/lazyAndCommands/lazy-devices-test.js +14 -18
- package/test/unit/ngsiv2/lazyAndCommands/polling-commands-test.js +3 -1
- package/test/unit/ngsiv2/ngsiService/active-devices-test.js +1 -0
- package/test/unit/ngsiv2/ngsiService/queryDeviceInformationInCb-test.js +0 -1
- package/test/unit/ngsiv2/ngsiService/subscriptions-test.js +4 -3
- package/test/unit/ngsiv2/plugins/bidirectional-plugin_test.js +3 -2
- package/test/unit/ngsiv2/plugins/multientity-plugin_test.js +210 -0
- package/test/unit/ngsiv2/plugins/translation-inPlugins_test.js +1 -1
- package/test/unit/ngsiv2/provisioning/device-group-api-test.js +3 -2
- package/test/unit/ngsiv2/provisioning/device-group-utils-test.js +2 -1
- package/test/unit/ngsiv2/provisioning/device-provisioning-api_test.js +2 -1
- package/test/unit/ngsiv2/provisioning/device-registration_test.js +3 -2
- package/test/unit/ngsiv2/provisioning/device-update-registration_test.js +4 -3
- package/test/unit/ngsiv2/provisioning/listProvisionedDevices-test.js +42 -53
- package/test/unit/ngsiv2/provisioning/provisionDeviceMultientity-test.js +2 -1
- package/test/unit/ngsiv2/provisioning/removeProvisionedDevice-test.js +4 -4
- package/test/unit/ngsiv2/provisioning/singleConfigurationMode-test.js +3 -4
- package/test/unit/ngsiv2/provisioning/updateProvisionedDevices-test.js +13 -19
- package/test/unit/plugins/capture-configuration-inPlugins_test.js +3 -1
- package/test/unit/plugins/capture-provision-inPlugins_test.js +2 -1
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin20.json +0 -25
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* Modified by: Federico M. Facca - Martel Innovate
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
-
const request = require('request');
|
|
26
|
+
const request = require('../../request-shim');
|
|
27
27
|
const async = require('async');
|
|
28
28
|
const errors = require('../../errors');
|
|
29
29
|
const constants = require('../../constants');
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* please contact with::daniel.moranjimenez@telefonica.com
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
-
const request = require('request');
|
|
24
|
+
const request = require('../../request-shim');
|
|
25
25
|
const errors = require('../../errors');
|
|
26
26
|
const config = require('../../commonConfig');
|
|
27
27
|
const intoTrans = require('../common/domain').intoTrans;
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
|
|
27
27
|
/* eslint-disable consistent-return */
|
|
28
28
|
|
|
29
|
-
const request = require('request');
|
|
29
|
+
const request = require('../../request-shim');
|
|
30
30
|
const queryString = require('query-string');
|
|
31
31
|
const errors = require('../../errors');
|
|
32
32
|
const config = require('../../commonConfig');
|
|
@@ -64,7 +64,8 @@ function auth(trust, callback) {
|
|
|
64
64
|
'Content-Length': formData.length,
|
|
65
65
|
'Content-Type': 'application/x-www-form-urlencoded'
|
|
66
66
|
},
|
|
67
|
-
body: formData
|
|
67
|
+
body: formData,
|
|
68
|
+
responseType: 'text'
|
|
68
69
|
};
|
|
69
70
|
|
|
70
71
|
logger.debug(context, 'Authentication on the OAuth2 provider [%s]', url);
|
|
@@ -289,6 +289,7 @@ function update(device, callback) {
|
|
|
289
289
|
data.internalAttributes = device.internalAttributes;
|
|
290
290
|
data.commands = device.commands;
|
|
291
291
|
data.endpoint = device.endpoint;
|
|
292
|
+
data.polling = device.polling;
|
|
292
293
|
data.name = device.name;
|
|
293
294
|
data.type = device.type;
|
|
294
295
|
data.apikey = device.apikey;
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
|
|
28
28
|
/* eslint-disable consistent-return */
|
|
29
29
|
|
|
30
|
-
const request = require('request');
|
|
30
|
+
const request = require('../../request-shim');
|
|
31
31
|
const async = require('async');
|
|
32
32
|
const apply = async.apply;
|
|
33
33
|
const uuid = require('uuid');
|
|
@@ -112,11 +112,7 @@ function createInitialEntityHandlerNgsi2(deviceData, newDevice, callback) {
|
|
|
112
112
|
function updateEntityHandlerNgsi2(deviceData, updatedDevice, callback) {
|
|
113
113
|
return function handleEntityResponse(error, response, body) {
|
|
114
114
|
if (error) {
|
|
115
|
-
logger.error(
|
|
116
|
-
context,
|
|
117
|
-
'ORION-001: Connection error updating entity in the Context Broker: %s',
|
|
118
|
-
error
|
|
119
|
-
);
|
|
115
|
+
logger.error(context, 'ORION-001: Connection error updating entity in the Context Broker: %s', error);
|
|
120
116
|
|
|
121
117
|
alarms.raise(constants.ORION_ALARM, error);
|
|
122
118
|
|
|
@@ -136,7 +136,6 @@ function sendUnregistrationsNgsi2(deviceData, callback) {
|
|
|
136
136
|
const options = {
|
|
137
137
|
url: cbHost + '/v2/registrations/' + deviceData.registrationId,
|
|
138
138
|
method: 'DELETE',
|
|
139
|
-
json: true,
|
|
140
139
|
headers: {
|
|
141
140
|
'fiware-service': deviceData.service,
|
|
142
141
|
'fiware-servicepath': deviceData.subservice
|
|
@@ -177,7 +176,6 @@ function sendUnregistrationsNgsiLD(deviceData, callback) {
|
|
|
177
176
|
const options = {
|
|
178
177
|
url: cbHost + '/ngsi-ld/v1/csourceRegistrations/' + deviceData.registrationId,
|
|
179
178
|
method: 'DELETE',
|
|
180
|
-
json: true,
|
|
181
179
|
headers: {
|
|
182
180
|
'fiware-service': deviceData.service,
|
|
183
181
|
'fiware-servicepath': deviceData.subservice,
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
/* eslint-disable consistent-return */
|
|
27
27
|
|
|
28
|
-
const request = require('request');
|
|
28
|
+
const request = require('../../request-shim');
|
|
29
29
|
const statsService = require('./../stats/statsRegistry');
|
|
30
30
|
const async = require('async');
|
|
31
31
|
const apply = async.apply;
|
|
@@ -34,6 +34,7 @@ const errors = require('../../errors');
|
|
|
34
34
|
const utils = require('../northBound/restUtils');
|
|
35
35
|
const config = require('../../commonConfig');
|
|
36
36
|
const constants = require('../../constants');
|
|
37
|
+
const jexlParser = require('../../plugins/jexlParser');
|
|
37
38
|
const moment = require('moment-timezone');
|
|
38
39
|
const logger = require('logops');
|
|
39
40
|
const _ = require('underscore');
|
|
@@ -55,8 +56,9 @@ const NGSI_LD_URN = 'urn:ngsi-ld:';
|
|
|
55
56
|
* format
|
|
56
57
|
*/
|
|
57
58
|
|
|
58
|
-
function
|
|
59
|
-
|
|
59
|
+
function convertAttrNGSILD(attr) {
|
|
60
|
+
// eslint eqeqeq - deliberate double equals to include undefined.
|
|
61
|
+
if (attr.value == null || Number.isNaN(attr.value)) {
|
|
60
62
|
return undefined;
|
|
61
63
|
}
|
|
62
64
|
let obj = { type: 'Property', value: attr.value };
|
|
@@ -178,7 +180,7 @@ function convertNGSIv2ToLD(attr) {
|
|
|
178
180
|
obj.unitCode = attr.metadata[key].value;
|
|
179
181
|
break;
|
|
180
182
|
default:
|
|
181
|
-
obj[key] =
|
|
183
|
+
obj[key] = convertAttrNGSILD(attr.metadata[key]);
|
|
182
184
|
}
|
|
183
185
|
});
|
|
184
186
|
delete obj.TimeInstant;
|
|
@@ -214,7 +216,7 @@ function formatAsNGSILD(json) {
|
|
|
214
216
|
// element for NSGI-LD.
|
|
215
217
|
break;
|
|
216
218
|
default:
|
|
217
|
-
obj[key] =
|
|
219
|
+
obj[key] = convertAttrNGSILD(json[key]);
|
|
218
220
|
}
|
|
219
221
|
});
|
|
220
222
|
|
|
@@ -329,7 +331,6 @@ function sendQueryValueNgsiLD(entityName, attributes, typeInformation, token, ca
|
|
|
329
331
|
|
|
330
332
|
const options = NGSIUtils.createRequestObject(url, typeInformation, token);
|
|
331
333
|
options.method = 'GET';
|
|
332
|
-
options.json = true;
|
|
333
334
|
|
|
334
335
|
if (!typeInformation || !typeInformation.type) {
|
|
335
336
|
callback(new errors.TypeNotFound(null, entityName));
|
|
@@ -402,6 +403,90 @@ function addLinkedEntities(typeInformation, json) {
|
|
|
402
403
|
});
|
|
403
404
|
}
|
|
404
405
|
|
|
406
|
+
/**
|
|
407
|
+
* Remove id, type and any hidden attrs after processing
|
|
408
|
+
*
|
|
409
|
+
* @param {Object} enities Unprocessed entities
|
|
410
|
+
* @param {Object} typeInformation Configuration information for the device.
|
|
411
|
+
*/
|
|
412
|
+
function removeHiddenAttrsFromMultiEntity(entities, typeInformation) {
|
|
413
|
+
var explicitAttrsList = [];
|
|
414
|
+
if (typeInformation.explicitAttrs) {
|
|
415
|
+
explicitAttrsList.push('type');
|
|
416
|
+
explicitAttrsList.push('id');
|
|
417
|
+
if (typeof typeInformation.explicitAttrs === 'boolean') {
|
|
418
|
+
if (typeInformation.timestamp) {
|
|
419
|
+
explicitAttrsList.push(constants.TIMESTAMP_ATTRIBUTE);
|
|
420
|
+
}
|
|
421
|
+
if (typeInformation.active) {
|
|
422
|
+
typeInformation.active.forEach((attr) => {
|
|
423
|
+
explicitAttrsList.push(attr.name);
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
if (typeInformation.staticAttributes) {
|
|
427
|
+
typeInformation.staticAttributes.forEach((attr) => {
|
|
428
|
+
explicitAttrsList.push(attr.name);
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
} else if (typeof typeInformation.explicitAttrs === 'string') {
|
|
432
|
+
entities.forEach((entity) => {
|
|
433
|
+
const attsArray = utils.extractAttributesArrayFromNgsi2Entity(entity);
|
|
434
|
+
const ctx = jexlParser.extractContext(attsArray);
|
|
435
|
+
const res = jexlParser.parse(typeInformation.explicitAttrs, ctx);
|
|
436
|
+
explicitAttrsList = explicitAttrsList.concat(res);
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
if (explicitAttrsList.length > 0) {
|
|
441
|
+
entities.forEach((entity) => {
|
|
442
|
+
const hidden = _.difference(_.keys(entity), explicitAttrsList);
|
|
443
|
+
hidden.forEach((attr) => {
|
|
444
|
+
delete entity[attr];
|
|
445
|
+
});
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
return entities;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Remove id, type and any hidden attrs after processing
|
|
453
|
+
*
|
|
454
|
+
* @param {Object} result Unprocessed entity
|
|
455
|
+
* @param {Object} typeInformation Configuration information for the device.
|
|
456
|
+
*/
|
|
457
|
+
function removeHiddenAttrs(result, typeInformation) {
|
|
458
|
+
delete result.id;
|
|
459
|
+
delete result.type;
|
|
460
|
+
var explicitAttrsList = [];
|
|
461
|
+
if (typeInformation.explicitAttrs && typeof typeInformation.explicitAttrs === 'boolean') {
|
|
462
|
+
if (typeInformation.timestamp) {
|
|
463
|
+
explicitAttrsList.push(constants.TIMESTAMP_ATTRIBUTE);
|
|
464
|
+
}
|
|
465
|
+
if (typeInformation.active) {
|
|
466
|
+
typeInformation.active.forEach((attr) => {
|
|
467
|
+
explicitAttrsList.push(attr.name);
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
if (typeInformation.staticAttributes) {
|
|
471
|
+
typeInformation.staticAttributes.forEach((attr) => {
|
|
472
|
+
explicitAttrsList.push(attr.name);
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
} else if (typeInformation.explicitAttrs && typeof typeInformation.explicitAttrs === 'string') {
|
|
476
|
+
const attsArray = utils.extractAttributesArrayFromNgsi2Entity(result);
|
|
477
|
+
const ctx = jexlParser.extractContext(attsArray);
|
|
478
|
+
const res = jexlParser.parse(typeInformation.explicitAttrs, ctx);
|
|
479
|
+
explicitAttrsList = res;
|
|
480
|
+
}
|
|
481
|
+
if (explicitAttrsList.length > 0) {
|
|
482
|
+
const hidden = _.difference(_.keys(result), explicitAttrsList);
|
|
483
|
+
hidden.forEach((attr) => {
|
|
484
|
+
delete result[attr];
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
return result;
|
|
488
|
+
}
|
|
489
|
+
|
|
405
490
|
/**
|
|
406
491
|
* Makes an update in the Device's entity in the context broker, with the values given in the 'attributes' array.
|
|
407
492
|
* This array should comply to the NGSI-LD's attribute format.
|
|
@@ -413,7 +498,6 @@ function addLinkedEntities(typeInformation, json) {
|
|
|
413
498
|
*/
|
|
414
499
|
function sendUpdateValueNgsiLD(entityName, attributes, typeInformation, token, callback) {
|
|
415
500
|
let payload = {};
|
|
416
|
-
|
|
417
501
|
const url = '/ngsi-ld/v1/entityOperations/upsert/?options=update';
|
|
418
502
|
|
|
419
503
|
const options = NGSIUtils.createRequestObject(url, typeInformation, token);
|
|
@@ -474,11 +558,10 @@ function sendUpdateValueNgsiLD(entityName, attributes, typeInformation, token, c
|
|
|
474
558
|
}
|
|
475
559
|
}
|
|
476
560
|
|
|
477
|
-
options.json = result;
|
|
561
|
+
options.json = removeHiddenAttrsFromMultiEntity(result, typeInformation);
|
|
478
562
|
} else {
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
options.json = result;
|
|
563
|
+
// Remove id, type and any hidden attrs after processing
|
|
564
|
+
options.json = removeHiddenAttrs(result, typeInformation);
|
|
482
565
|
logger.debug(context, 'typeInformation: %j', typeInformation);
|
|
483
566
|
if (
|
|
484
567
|
'timestamp' in typeInformation && typeInformation.timestamp !== undefined
|
|
@@ -567,6 +650,7 @@ function sendUpdateValueNgsiLD(entityName, attributes, typeInformation, token, c
|
|
|
567
650
|
);
|
|
568
651
|
}
|
|
569
652
|
|
|
653
|
+
exports.convertAttrNGSILD = convertAttrNGSILD;
|
|
570
654
|
exports.formatAsNGSILD = formatAsNGSILD;
|
|
571
655
|
exports.sendUpdateValue = sendUpdateValueNgsiLD;
|
|
572
656
|
exports.sendQueryValue = sendQueryValueNgsiLD;
|
|
@@ -27,21 +27,24 @@
|
|
|
27
27
|
|
|
28
28
|
/* eslint-disable consistent-return */
|
|
29
29
|
|
|
30
|
-
const request = require('request');
|
|
30
|
+
const request = require('../../request-shim');
|
|
31
31
|
const statsService = require('./../stats/statsRegistry');
|
|
32
32
|
const async = require('async');
|
|
33
33
|
const apply = async.apply;
|
|
34
34
|
const alarms = require('../common/alarmManagement');
|
|
35
35
|
const errors = require('../../errors');
|
|
36
36
|
const utils = require('../northBound/restUtils');
|
|
37
|
+
const pluginUtils = require('../../plugins/pluginUtils');
|
|
37
38
|
const config = require('../../commonConfig');
|
|
38
39
|
const constants = require('../../constants');
|
|
40
|
+
const jexlParser = require('../../plugins/jexlParser');
|
|
39
41
|
const moment = require('moment-timezone');
|
|
40
42
|
const NGSIUtils = require('./ngsiUtils');
|
|
41
43
|
const logger = require('logops');
|
|
42
44
|
const context = {
|
|
43
45
|
op: 'IoTAgentNGSI.Entities-v2'
|
|
44
46
|
};
|
|
47
|
+
const _ = require('underscore');
|
|
45
48
|
|
|
46
49
|
/**
|
|
47
50
|
* Amends an NGSIv2 Geoattribute from String to GeoJSON format
|
|
@@ -290,7 +293,6 @@ function sendQueryValueNgsi2(entityName, attributes, typeInformation, token, cal
|
|
|
290
293
|
|
|
291
294
|
const options = NGSIUtils.createRequestObject(url, typeInformation, token);
|
|
292
295
|
options.method = 'GET';
|
|
293
|
-
options.json = true;
|
|
294
296
|
|
|
295
297
|
if (!typeInformation || !typeInformation.type) {
|
|
296
298
|
callback(new errors.TypeNotFound(null, entityName));
|
|
@@ -312,6 +314,92 @@ function sendQueryValueNgsi2(entityName, attributes, typeInformation, token, cal
|
|
|
312
314
|
);
|
|
313
315
|
}
|
|
314
316
|
|
|
317
|
+
/**
|
|
318
|
+
* Remove id, type and any hidden attrs after processing
|
|
319
|
+
*
|
|
320
|
+
* @param {Object} enities Unprocessed entities
|
|
321
|
+
* @param {Object} typeInformation Configuration information for the device.
|
|
322
|
+
*/
|
|
323
|
+
function removeHiddenAttrsFromMultiEntity(entities, typeInformation) {
|
|
324
|
+
var explicitAttrsList = [];
|
|
325
|
+
if (typeInformation.explicitAttrs) {
|
|
326
|
+
explicitAttrsList.push('type');
|
|
327
|
+
explicitAttrsList.push('id');
|
|
328
|
+
if (typeof typeInformation.explicitAttrs === 'boolean') {
|
|
329
|
+
if (typeInformation.timestamp) {
|
|
330
|
+
explicitAttrsList.push(constants.TIMESTAMP_ATTRIBUTE);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
if (typeInformation.active) {
|
|
334
|
+
typeInformation.active.forEach((attr) => {
|
|
335
|
+
explicitAttrsList.push(attr.name);
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
if (typeInformation.staticAttributes) {
|
|
339
|
+
typeInformation.staticAttributes.forEach((attr) => {
|
|
340
|
+
explicitAttrsList.push(attr.name);
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
} else if (typeof typeInformation.explicitAttrs === 'string') {
|
|
344
|
+
entities.forEach((entity) => {
|
|
345
|
+
const attsArray = pluginUtils.extractAttributesArrayFromNgsi2Entity(entity);
|
|
346
|
+
const ctx = jexlParser.extractContext(attsArray);
|
|
347
|
+
const res = jexlParser.applyExpression(typeInformation.explicitAttrs, ctx, typeInformation);
|
|
348
|
+
explicitAttrsList = explicitAttrsList.concat(res);
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
if (explicitAttrsList.length > 0) {
|
|
353
|
+
logger.debug(context, 'removeHiddenAttrsFromMultiEntity %s', explicitAttrsList);
|
|
354
|
+
entities.forEach((entity) => {
|
|
355
|
+
const hidden = _.difference(_.keys(entity), explicitAttrsList);
|
|
356
|
+
hidden.forEach((attr) => {
|
|
357
|
+
delete entity[attr];
|
|
358
|
+
});
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
return entities;
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Remove id, type and any hidden attrs after processing
|
|
365
|
+
*
|
|
366
|
+
* @param {Object} result An Unprocessed entity
|
|
367
|
+
* @param {Object} typeInformation Configuration information for the device.
|
|
368
|
+
*/
|
|
369
|
+
function removeHiddenAttrs(result, typeInformation) {
|
|
370
|
+
delete result.id;
|
|
371
|
+
delete result.type;
|
|
372
|
+
var explicitAttrsList = [];
|
|
373
|
+
if (typeInformation.explicitAttrs && typeof typeInformation.explicitAttrs === 'boolean') {
|
|
374
|
+
if (typeInformation.timestamp) {
|
|
375
|
+
explicitAttrsList.push(constants.TIMESTAMP_ATTRIBUTE);
|
|
376
|
+
}
|
|
377
|
+
if (typeInformation.active) {
|
|
378
|
+
typeInformation.active.forEach((attr) => {
|
|
379
|
+
explicitAttrsList.push(attr.name);
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
if (typeInformation.staticAttributes) {
|
|
383
|
+
typeInformation.staticAttributes.forEach((attr) => {
|
|
384
|
+
explicitAttrsList.push(attr.name);
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
} else if (typeInformation.explicitAttrs && typeof typeInformation.explicitAttrs === 'string') {
|
|
388
|
+
const attsArray = pluginUtils.extractAttributesArrayFromNgsi2Entity(result);
|
|
389
|
+
const ctx = jexlParser.extractContext(attsArray);
|
|
390
|
+
const res = jexlParser.applyExpression(typeInformation.explicitAttrs, ctx, typeInformation);
|
|
391
|
+
explicitAttrsList = res;
|
|
392
|
+
}
|
|
393
|
+
if (explicitAttrsList.length > 0) {
|
|
394
|
+
logger.debug(context, 'removeHiddenAttrs %s', explicitAttrsList);
|
|
395
|
+
const hidden = _.difference(_.keys(result), explicitAttrsList);
|
|
396
|
+
hidden.forEach((attr) => {
|
|
397
|
+
delete result[attr];
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
return result;
|
|
401
|
+
}
|
|
402
|
+
|
|
315
403
|
/**
|
|
316
404
|
* Makes an update in the Device's entity in the context broker, with the values given in the 'attributes' array. This
|
|
317
405
|
* array should comply to the NGSIv2's attribute format.
|
|
@@ -326,7 +414,7 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca
|
|
|
326
414
|
|
|
327
415
|
let url = '/v2/entities/' + entityName + '/attrs';
|
|
328
416
|
|
|
329
|
-
if (typeInformation.type) {
|
|
417
|
+
if (typeInformation && typeInformation.type) {
|
|
330
418
|
url += '?type=' + typeInformation.type;
|
|
331
419
|
}
|
|
332
420
|
|
|
@@ -359,7 +447,6 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca
|
|
|
359
447
|
//overwritte if id or type missnamed atributes reach this point
|
|
360
448
|
payload.id = entityName;
|
|
361
449
|
payload.type = typeInformation.type;
|
|
362
|
-
|
|
363
450
|
payload = NGSIUtils.castJsonNativeAttributes(payload);
|
|
364
451
|
async.waterfall(
|
|
365
452
|
[
|
|
@@ -392,7 +479,7 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca
|
|
|
392
479
|
}
|
|
393
480
|
options.json = {
|
|
394
481
|
actionType: 'append',
|
|
395
|
-
entities: result
|
|
482
|
+
entities: removeHiddenAttrsFromMultiEntity(result, typeInformation)
|
|
396
483
|
};
|
|
397
484
|
if (config.getConfig().appendMode === true) {
|
|
398
485
|
options.json.actionType = 'append';
|
|
@@ -400,9 +487,7 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca
|
|
|
400
487
|
options.json.actionType = 'update';
|
|
401
488
|
}
|
|
402
489
|
} else {
|
|
403
|
-
|
|
404
|
-
delete result.type;
|
|
405
|
-
options.json = result;
|
|
490
|
+
options.json = removeHiddenAttrs(result, typeInformation);
|
|
406
491
|
logger.debug(context, 'typeInformation: %j', typeInformation);
|
|
407
492
|
if (
|
|
408
493
|
'timestamp' in typeInformation && typeInformation.timestamp !== undefined
|
|
@@ -132,9 +132,10 @@ function executeWithDeviceInformation(operationFunction) {
|
|
|
132
132
|
attributes,
|
|
133
133
|
deviceInformation
|
|
134
134
|
);
|
|
135
|
-
|
|
135
|
+
const currentType = type ? type : deviceInformation.type;
|
|
136
|
+
config.getGroupRegistry().getType(currentType, function (error, deviceGroup) {
|
|
136
137
|
let typeInformation;
|
|
137
|
-
const configDeviceInfo = config.getConfig().types[
|
|
138
|
+
const configDeviceInfo = config.getConfig().types[currentType];
|
|
138
139
|
if (error) {
|
|
139
140
|
logger.debug(context, 'error %j in get group device', error);
|
|
140
141
|
}
|
|
@@ -40,6 +40,7 @@ const context = {
|
|
|
40
40
|
const updateContextTemplateNgsiLD = require('../../templates/updateContextNgsiLD.json');
|
|
41
41
|
const notificationTemplateNgsiLD = require('../../templates/notificationTemplateNgsiLD.json');
|
|
42
42
|
const contextServerUtils = require('./contextServerUtils');
|
|
43
|
+
const ngsiLD = require('../ngsi/entities-NGSI-LD');
|
|
43
44
|
|
|
44
45
|
const updatePaths = ['/ngsi-ld/v1/entities/:entity/attrs/:attr'];
|
|
45
46
|
const queryPaths = ['/ngsi-ld/v1/entities/:entity'];
|
|
@@ -250,10 +251,10 @@ function defaultQueryHandlerNgsiLD(id, type, service, subservice, attributes, ca
|
|
|
250
251
|
attributeType = lazyAttribute.type;
|
|
251
252
|
}
|
|
252
253
|
|
|
253
|
-
contextElement[attributes[i]] = {
|
|
254
|
+
contextElement[attributes[i]] = ngsiLD.convertAttrNGSILD({
|
|
254
255
|
type: attributeType,
|
|
255
256
|
value: ''
|
|
256
|
-
};
|
|
257
|
+
});
|
|
257
258
|
}
|
|
258
259
|
|
|
259
260
|
callback(null, contextElement);
|
|
@@ -34,6 +34,7 @@ const context = {
|
|
|
34
34
|
};
|
|
35
35
|
const apply = async.apply;
|
|
36
36
|
let provisioningHandler;
|
|
37
|
+
let updatingHandler;
|
|
37
38
|
let removeDeviceHandler;
|
|
38
39
|
let updateDeviceTemplate;
|
|
39
40
|
let createDeviceTemplate;
|
|
@@ -53,6 +54,7 @@ const provisioningAPITranslation = {
|
|
|
53
54
|
protocol: 'protocol',
|
|
54
55
|
transport: 'transport',
|
|
55
56
|
endpoint: 'endpoint',
|
|
57
|
+
polling: 'polling',
|
|
56
58
|
attributes: 'active',
|
|
57
59
|
commands: 'commands',
|
|
58
60
|
lazy: 'lazy',
|
|
@@ -204,6 +206,7 @@ function toProvisioningAPIFormat(device) {
|
|
|
204
206
|
timezone: device.timezone,
|
|
205
207
|
timestamp: device.timestamp,
|
|
206
208
|
endpoint: device.endpoint,
|
|
209
|
+
polling: device.polling,
|
|
207
210
|
transport: device.transport,
|
|
208
211
|
attributes: device.active ? device.active.map(attributeToProvisioningAPIFormat) : undefined,
|
|
209
212
|
lazy: device.lazy ? device.lazy.map(attributeToProvisioningAPIFormat) : undefined,
|
|
@@ -317,6 +320,14 @@ function handleRemoveDevice(req, res, next) {
|
|
|
317
320
|
* This middleware handles updates in the provisioning devices. The only attribute
|
|
318
321
|
*/
|
|
319
322
|
function handleUpdateDevice(req, res, next) {
|
|
323
|
+
function applyUpdatingHandler(device, callback) {
|
|
324
|
+
if (updatingHandler) {
|
|
325
|
+
updatingHandler(device, callback);
|
|
326
|
+
} else {
|
|
327
|
+
callback(null, device);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
320
331
|
if (req.body.device_id) {
|
|
321
332
|
next(new errors.BadRequest("Can't change the ID of a preprovisioned device"));
|
|
322
333
|
} else {
|
|
@@ -338,12 +349,19 @@ function handleUpdateDevice(req, res, next) {
|
|
|
338
349
|
if (req.body.entity_name || req.body.entity_type) {
|
|
339
350
|
isTypeOrNameUpdated = true;
|
|
340
351
|
}
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
352
|
+
async.waterfall([apply(applyUpdatingHandler, newDevice)], function handleUpdating(
|
|
353
|
+
error,
|
|
354
|
+
newDeviceUpdated
|
|
355
|
+
) {
|
|
356
|
+
deviceService.updateRegister(newDeviceUpdated, isTypeOrNameUpdated, function handleDeviceUpdate(
|
|
357
|
+
error
|
|
358
|
+
) {
|
|
359
|
+
if (error) {
|
|
360
|
+
next(error);
|
|
361
|
+
} else {
|
|
362
|
+
res.status(204).json({});
|
|
363
|
+
}
|
|
364
|
+
});
|
|
347
365
|
});
|
|
348
366
|
} else {
|
|
349
367
|
next(new errors.DeviceNotFound(req.params.deviceId));
|
|
@@ -392,6 +410,10 @@ function setProvisioningHandler(newHandler) {
|
|
|
392
410
|
provisioningHandler = newHandler;
|
|
393
411
|
}
|
|
394
412
|
|
|
413
|
+
function setUpdatingHandler(newHandler) {
|
|
414
|
+
updatingHandler = newHandler;
|
|
415
|
+
}
|
|
416
|
+
|
|
395
417
|
function setRemoveDeviceHandler(newHandler) {
|
|
396
418
|
removeDeviceHandler = newHandler;
|
|
397
419
|
}
|
|
@@ -409,6 +431,7 @@ function clear(callback) {
|
|
|
409
431
|
exports.setConfiguration = setConfiguration;
|
|
410
432
|
exports.loadContextRoutes = intoTrans(context, loadContextRoutes);
|
|
411
433
|
exports.setProvisioningHandler = intoTrans(context, setProvisioningHandler);
|
|
434
|
+
exports.setUpdatingHandler = intoTrans(context, setUpdatingHandler);
|
|
412
435
|
exports.setRemoveDeviceHandler = intoTrans(context, setRemoveDeviceHandler);
|
|
413
436
|
exports.addDeviceProvisionMiddleware = addDeviceProvisionMiddleware;
|
|
414
437
|
exports.clear = clear;
|
|
@@ -31,6 +31,7 @@ const domainUtils = require('../common/domain');
|
|
|
31
31
|
const middlewares = require('../common/genericMiddleware');
|
|
32
32
|
const intoTrans = domainUtils.intoTrans;
|
|
33
33
|
const deviceProvisioning = require('./deviceProvisioningServer');
|
|
34
|
+
const deviceUpdating = require('./deviceProvisioningServer');
|
|
34
35
|
const groupProvisioning = require('./deviceGroupAdministrationServer');
|
|
35
36
|
const logger = require('logops');
|
|
36
37
|
const context = {
|
|
@@ -116,6 +117,7 @@ exports.setNotificationHandler = intoTrans(context, contextServer.setNotificatio
|
|
|
116
117
|
exports.setConfigurationHandler = intoTrans(context, groupProvisioning.setConfigurationHandler);
|
|
117
118
|
exports.setRemoveConfigurationHandler = intoTrans(context, groupProvisioning.setRemoveConfigurationHandler);
|
|
118
119
|
exports.setProvisioningHandler = intoTrans(context, deviceProvisioning.setProvisioningHandler);
|
|
120
|
+
exports.setUpdatingHandler = intoTrans(context, deviceUpdating.setUpdatingHandler);
|
|
119
121
|
exports.setRemoveDeviceHandler = intoTrans(context, deviceProvisioning.setRemoveDeviceHandler);
|
|
120
122
|
exports.addDeviceProvisionMiddleware = deviceProvisioning.addDeviceProvisionMiddleware;
|
|
121
123
|
exports.addConfigurationProvisionMiddleware = groupProvisioning.addConfigurationProvisionMiddleware;
|
|
@@ -35,7 +35,7 @@ const context = {
|
|
|
35
35
|
op: 'IoTAgentNGSI.RestUtils'
|
|
36
36
|
};
|
|
37
37
|
const _ = require('underscore');
|
|
38
|
-
const request = require('request');
|
|
38
|
+
const request = require('../../request-shim');
|
|
39
39
|
const async = require('async');
|
|
40
40
|
const apply = async.apply;
|
|
41
41
|
const ngsiService = require('../ngsi/ngsiService');
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "iotagent-node-lib",
|
|
3
3
|
"license": "AGPL-3.0-only",
|
|
4
4
|
"description": "IoT Agent library to interface with NGSI Context Broker",
|
|
5
|
-
"version": "2.
|
|
5
|
+
"version": "2.19.0",
|
|
6
6
|
"homepage": "https://github.com/telefonicaid/iotagent-node-lib",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"fiware",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"lint:text": "textlint '*.md' 'doc/*.md'",
|
|
37
37
|
"prettier": "prettier --config .prettierrc.json --write '**/**/**/**/*.js' '**/**/**/*.js' '**/**/*.js' '**/*.js' '*.js'",
|
|
38
38
|
"prettier:text": "prettier 'README.md' 'doc/*.md' 'doc/**/*.md' --no-config --tab-width 4 --print-width 120 --write --prose-wrap always",
|
|
39
|
-
"test": "nyc --reporter=text mocha --recursive 'test/**/*.js' --reporter spec --timeout
|
|
39
|
+
"test": "nyc --reporter=text mocha --recursive 'test/**/*.js' --reporter spec --timeout 8000 --ui bdd --exit --color true",
|
|
40
40
|
"test:expression": "nyc --reporter=text mocha --recursive 'test/unit/expressions/*.js' --reporter spec --timeout 5000 --ui bdd --exit --color true",
|
|
41
41
|
"test:multientity": "nyc --reporter=text mocha --recursive 'test/unit/ngsiv2/plugins/multientity-plugin_test.js' --reporter spec --timeout 5000 --ui bdd --exit --color true",
|
|
42
42
|
"test:debug": "mocha --recursive 'test/**/*.js' --reporter spec --inspect-brk --timeout 30000 --ui bdd --exit",
|
|
@@ -50,16 +50,16 @@
|
|
|
50
50
|
"body-parser": "~1.19.0",
|
|
51
51
|
"command-shell-lib": "1.0.0",
|
|
52
52
|
"express": "~4.16.4",
|
|
53
|
+
"got": "~11.8.2",
|
|
53
54
|
"jexl": "2.3.0",
|
|
54
55
|
"jison": "0.4.18",
|
|
55
|
-
"logops": "2.1.
|
|
56
|
+
"logops": "2.1.2",
|
|
56
57
|
"moment": "~2.24.0",
|
|
57
58
|
"moment-timezone": "~0.5.25",
|
|
58
59
|
"mongodb": "3.6.8",
|
|
59
60
|
"mongoose": "5.7.7",
|
|
60
61
|
"mu2": "~0.5.20",
|
|
61
62
|
"query-string": "6.5.0",
|
|
62
|
-
"request": "2.88.0",
|
|
63
63
|
"revalidator": "~0.3.1",
|
|
64
64
|
"underscore": "~1.12.1",
|
|
65
65
|
"uuid": "~3.3.2"
|
package/test/tools/utils.js
CHANGED
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
24
|
const fs = require('fs');
|
|
25
|
+
const request = require('../../lib/fiware-iotagent-lib').request;
|
|
25
26
|
|
|
26
27
|
function readExampleFile(name, raw) {
|
|
27
28
|
let text = null;
|
|
@@ -36,3 +37,4 @@ function readExampleFile(name, raw) {
|
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
exports.readExampleFile = readExampleFile;
|
|
40
|
+
exports.request = request;
|