iotagent-node-lib 2.18.0 → 2.21.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/.nyc_output/76bc24ff-5fac-4b5a-997d-de2799342eb0.json +1 -0
- package/.nyc_output/processinfo/76bc24ff-5fac-4b5a-997d-de2799342eb0.json +1 -0
- package/.nyc_output/processinfo/index.json +1 -0
- package/.readthedocs.yml +3 -1
- package/CHANGES_NEXT_RELEASE +1 -0
- package/README.md +5 -56
- package/doc/advanced-topics.md +121 -85
- package/doc/api.md +63 -54
- package/doc/development.md +8 -9
- package/doc/expressionLanguage.md +517 -316
- package/doc/installationguide.md +66 -64
- package/doc/northboundinteractions.md +40 -33
- package/doc/requirements.txt +4 -0
- package/{docs → doc}/roadmap.md +21 -6
- package/doc/usermanual.md +50 -18
- package/docker/Mosquitto/Dockerfile +28 -11
- package/docker/Mosquitto/README.md +8 -6
- package/docker/Mosquitto/startMosquitto.sh +14 -4
- package/lib/fiware-iotagent-lib.js +4 -2
- package/lib/jexlTranformsMap.js +11 -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 +63 -22
- package/lib/plugins/jexlParser.js +3 -1
- package/lib/plugins/multiEntity.js +2 -21
- package/lib/request-shim.js +111 -0
- package/lib/services/common/domain.js +6 -2
- 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/deviceRegistryMemory.js +13 -2
- package/lib/services/devices/deviceRegistryMongoDB.js +16 -7
- package/lib/services/devices/deviceService.js +26 -2
- 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 +97 -11
- package/lib/services/ngsi/entities-NGSI-v2.js +95 -8
- package/lib/services/ngsi/ngsiService.js +5 -4
- package/lib/services/northBound/contextServer-NGSI-LD.js +3 -2
- package/lib/services/northBound/contextServer-NGSI-v2.js +32 -27
- package/lib/services/northBound/contextServerUtils.js +1 -1
- package/lib/services/northBound/deviceProvisioningServer.js +31 -6
- package/lib/services/northBound/northboundServer.js +2 -0
- package/lib/services/northBound/restUtils.js +1 -1
- package/lib/templates/createDevice.json +12 -0
- package/lib/templates/updateDevice.json +12 -0
- package/package.json +9 -15
- 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/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/updateContextExpressionPlugin35.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin36.json +1 -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 +561 -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/bin/agentConsole.js +0 -257
- package/bin/iotAgentTester.js +0 -44
- package/lib/command/commandLine.js +0 -918
- package/lib/command/migration.js +0 -176
- package/test/unit/general/migration-test.js +0 -256
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin20.json +0 -25
|
@@ -214,7 +214,13 @@ function findConfigurationGroup(deviceObj, callback) {
|
|
|
214
214
|
} else {
|
|
215
215
|
config
|
|
216
216
|
.getGroupRegistry()
|
|
217
|
-
.findTypeSilently(
|
|
217
|
+
.findTypeSilently(
|
|
218
|
+
deviceObj.service,
|
|
219
|
+
deviceObj.subservice,
|
|
220
|
+
deviceObj.type,
|
|
221
|
+
deviceObj.apikey,
|
|
222
|
+
handlerGroupFindByType
|
|
223
|
+
);
|
|
218
224
|
}
|
|
219
225
|
}
|
|
220
226
|
|
|
@@ -513,6 +519,18 @@ function getDeviceByName(deviceName, service, subservice, callback) {
|
|
|
513
519
|
config.getRegistry().getByName(deviceName, service, subservice, callback);
|
|
514
520
|
}
|
|
515
521
|
|
|
522
|
+
/**
|
|
523
|
+
* Retrieve a device from the registry based on its entity name and type
|
|
524
|
+
*
|
|
525
|
+
* @param {String} deviceName Name of the entity associated to a device.
|
|
526
|
+
* @param {String} deviceType Type of the entity associated to a device.
|
|
527
|
+
* @param {String} service Service the device belongs to.
|
|
528
|
+
* @param {String} subservice Division inside the service.
|
|
529
|
+
*/
|
|
530
|
+
function getDeviceByNameAndType(deviceName, deviceType, service, subservice, callback) {
|
|
531
|
+
config.getRegistry().getByNameAndType(deviceName, deviceType, service, subservice, callback);
|
|
532
|
+
}
|
|
533
|
+
|
|
516
534
|
/**
|
|
517
535
|
* Retrieve a device from the registry based on the value of a given attribute.
|
|
518
536
|
*
|
|
@@ -581,7 +599,12 @@ function findOrCreate(deviceId, group, callback) {
|
|
|
581
599
|
callback(error, device, group);
|
|
582
600
|
});
|
|
583
601
|
} else {
|
|
584
|
-
logger.info(
|
|
602
|
+
logger.info(
|
|
603
|
+
context,
|
|
604
|
+
'Device %j not provisioned due autoprovision is disabled by its conf %j',
|
|
605
|
+
newDevice,
|
|
606
|
+
group
|
|
607
|
+
);
|
|
585
608
|
callback(new errors.DeviceNotFound(deviceId));
|
|
586
609
|
}
|
|
587
610
|
} else {
|
|
@@ -632,6 +655,7 @@ exports.getDevice = intoTrans(context, checkRegistry)(getDevice);
|
|
|
632
655
|
exports.getDeviceSilently = intoTrans(context, checkRegistry)(getDeviceSilently);
|
|
633
656
|
exports.getDevicesByAttribute = intoTrans(context, checkRegistry)(getDevicesByAttribute);
|
|
634
657
|
exports.getDeviceByName = intoTrans(context, checkRegistry)(getDeviceByName);
|
|
658
|
+
exports.getDeviceByNameAndType = intoTrans(context, checkRegistry)(getDeviceByNameAndType);
|
|
635
659
|
exports.register = intoTrans(context, registerDevice);
|
|
636
660
|
exports.updateRegister = intoTrans(context, updateRegisterDevice);
|
|
637
661
|
exports.unregister = intoTrans(context, unregisterDevice);
|
|
@@ -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,92 @@ 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
|
+
let explicitAttrsList;
|
|
414
|
+
if (typeInformation.explicitAttrs) {
|
|
415
|
+
explicitAttrsList = [];
|
|
416
|
+
explicitAttrsList.push('type');
|
|
417
|
+
explicitAttrsList.push('id');
|
|
418
|
+
if (typeof typeInformation.explicitAttrs === 'boolean') {
|
|
419
|
+
if (typeInformation.timestamp) {
|
|
420
|
+
explicitAttrsList.push(constants.TIMESTAMP_ATTRIBUTE);
|
|
421
|
+
}
|
|
422
|
+
if (typeInformation.active) {
|
|
423
|
+
typeInformation.active.forEach((attr) => {
|
|
424
|
+
explicitAttrsList.push(attr.name);
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
if (typeInformation.staticAttributes) {
|
|
428
|
+
typeInformation.staticAttributes.forEach((attr) => {
|
|
429
|
+
explicitAttrsList.push(attr.name);
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
} else if (typeof typeInformation.explicitAttrs === 'string') {
|
|
433
|
+
entities.forEach((entity) => {
|
|
434
|
+
const attsArray = utils.extractAttributesArrayFromNgsi2Entity(entity);
|
|
435
|
+
const ctx = jexlParser.extractContext(attsArray);
|
|
436
|
+
const res = jexlParser.parse(typeInformation.explicitAttrs, ctx);
|
|
437
|
+
explicitAttrsList = explicitAttrsList.concat(res);
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
if (explicitAttrsList && explicitAttrsList.length >= 0) {
|
|
442
|
+
entities.forEach((entity) => {
|
|
443
|
+
const hidden = _.difference(_.keys(entity), explicitAttrsList);
|
|
444
|
+
hidden.forEach((attr) => {
|
|
445
|
+
delete entity[attr];
|
|
446
|
+
});
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
return entities;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Remove id, type and any hidden attrs after processing
|
|
454
|
+
*
|
|
455
|
+
* @param {Object} result Unprocessed entity
|
|
456
|
+
* @param {Object} typeInformation Configuration information for the device.
|
|
457
|
+
*/
|
|
458
|
+
function removeHiddenAttrs(result, typeInformation) {
|
|
459
|
+
delete result.id;
|
|
460
|
+
delete result.type;
|
|
461
|
+
let explicitAttrsList;
|
|
462
|
+
if (typeInformation.explicitAttrs && typeof typeInformation.explicitAttrs === 'boolean') {
|
|
463
|
+
explicitAttrsList = [];
|
|
464
|
+
if (typeInformation.timestamp) {
|
|
465
|
+
explicitAttrsList.push(constants.TIMESTAMP_ATTRIBUTE);
|
|
466
|
+
}
|
|
467
|
+
if (typeInformation.active) {
|
|
468
|
+
typeInformation.active.forEach((attr) => {
|
|
469
|
+
explicitAttrsList.push(attr.name);
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
if (typeInformation.staticAttributes) {
|
|
473
|
+
typeInformation.staticAttributes.forEach((attr) => {
|
|
474
|
+
explicitAttrsList.push(attr.name);
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
} else if (typeInformation.explicitAttrs && typeof typeInformation.explicitAttrs === 'string') {
|
|
478
|
+
const attsArray = utils.extractAttributesArrayFromNgsi2Entity(result);
|
|
479
|
+
const ctx = jexlParser.extractContext(attsArray);
|
|
480
|
+
const res = jexlParser.parse(typeInformation.explicitAttrs, ctx);
|
|
481
|
+
explicitAttrsList = res;
|
|
482
|
+
}
|
|
483
|
+
if (explicitAttrsList && explicitAttrsList.length >= 0) {
|
|
484
|
+
const hidden = _.difference(_.keys(result), explicitAttrsList);
|
|
485
|
+
hidden.forEach((attr) => {
|
|
486
|
+
delete result[attr];
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
return result;
|
|
490
|
+
}
|
|
491
|
+
|
|
405
492
|
/**
|
|
406
493
|
* Makes an update in the Device's entity in the context broker, with the values given in the 'attributes' array.
|
|
407
494
|
* This array should comply to the NGSI-LD's attribute format.
|
|
@@ -413,7 +500,6 @@ function addLinkedEntities(typeInformation, json) {
|
|
|
413
500
|
*/
|
|
414
501
|
function sendUpdateValueNgsiLD(entityName, attributes, typeInformation, token, callback) {
|
|
415
502
|
let payload = {};
|
|
416
|
-
|
|
417
503
|
const url = '/ngsi-ld/v1/entityOperations/upsert/?options=update';
|
|
418
504
|
|
|
419
505
|
const options = NGSIUtils.createRequestObject(url, typeInformation, token);
|
|
@@ -474,11 +560,10 @@ function sendUpdateValueNgsiLD(entityName, attributes, typeInformation, token, c
|
|
|
474
560
|
}
|
|
475
561
|
}
|
|
476
562
|
|
|
477
|
-
options.json = result;
|
|
563
|
+
options.json = removeHiddenAttrsFromMultiEntity(result, typeInformation);
|
|
478
564
|
} else {
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
options.json = result;
|
|
565
|
+
// Remove id, type and any hidden attrs after processing
|
|
566
|
+
options.json = removeHiddenAttrs(result, typeInformation);
|
|
482
567
|
logger.debug(context, 'typeInformation: %j', typeInformation);
|
|
483
568
|
if (
|
|
484
569
|
'timestamp' in typeInformation && typeInformation.timestamp !== undefined
|
|
@@ -567,6 +652,7 @@ function sendUpdateValueNgsiLD(entityName, attributes, typeInformation, token, c
|
|
|
567
652
|
);
|
|
568
653
|
}
|
|
569
654
|
|
|
655
|
+
exports.convertAttrNGSILD = convertAttrNGSILD;
|
|
570
656
|
exports.formatAsNGSILD = formatAsNGSILD;
|
|
571
657
|
exports.sendUpdateValue = sendUpdateValueNgsiLD;
|
|
572
658
|
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,94 @@ 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
|
+
let explicitAttrsList;
|
|
325
|
+
if (typeInformation.explicitAttrs) {
|
|
326
|
+
explicitAttrsList = [];
|
|
327
|
+
explicitAttrsList.push('type');
|
|
328
|
+
explicitAttrsList.push('id');
|
|
329
|
+
if (typeof typeInformation.explicitAttrs === 'boolean') {
|
|
330
|
+
if (typeInformation.timestamp) {
|
|
331
|
+
explicitAttrsList.push(constants.TIMESTAMP_ATTRIBUTE);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
if (typeInformation.active) {
|
|
335
|
+
typeInformation.active.forEach((attr) => {
|
|
336
|
+
explicitAttrsList.push(attr.name);
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
if (typeInformation.staticAttributes) {
|
|
340
|
+
typeInformation.staticAttributes.forEach((attr) => {
|
|
341
|
+
explicitAttrsList.push(attr.name);
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
} else if (typeof typeInformation.explicitAttrs === 'string') {
|
|
345
|
+
entities.forEach((entity) => {
|
|
346
|
+
const attsArray = pluginUtils.extractAttributesArrayFromNgsi2Entity(entity);
|
|
347
|
+
const ctx = jexlParser.extractContext(attsArray);
|
|
348
|
+
const res = jexlParser.applyExpression(typeInformation.explicitAttrs, ctx, typeInformation);
|
|
349
|
+
explicitAttrsList = explicitAttrsList.concat(res);
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
if (explicitAttrsList && explicitAttrsList.length >= 0) {
|
|
354
|
+
entities.forEach((entity) => {
|
|
355
|
+
const hidden = _.difference(_.keys(entity), explicitAttrsList);
|
|
356
|
+
logger.debug(context, 'removeHiddenAttrsFromMultiEntity %s from entity %s', hidden, entity);
|
|
357
|
+
hidden.forEach((attr) => {
|
|
358
|
+
delete entity[attr];
|
|
359
|
+
});
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
return entities;
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Remove id, type and any hidden attrs after processing
|
|
366
|
+
*
|
|
367
|
+
* @param {Object} result An Unprocessed entity
|
|
368
|
+
* @param {Object} typeInformation Configuration information for the device.
|
|
369
|
+
*/
|
|
370
|
+
function removeHiddenAttrs(result, typeInformation) {
|
|
371
|
+
delete result.id;
|
|
372
|
+
delete result.type;
|
|
373
|
+
let explicitAttrsList;
|
|
374
|
+
if (typeInformation.explicitAttrs && typeof typeInformation.explicitAttrs === 'boolean') {
|
|
375
|
+
explicitAttrsList = [];
|
|
376
|
+
if (typeInformation.timestamp) {
|
|
377
|
+
explicitAttrsList.push(constants.TIMESTAMP_ATTRIBUTE);
|
|
378
|
+
}
|
|
379
|
+
if (typeInformation.active) {
|
|
380
|
+
typeInformation.active.forEach((attr) => {
|
|
381
|
+
explicitAttrsList.push(attr.name);
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
if (typeInformation.staticAttributes) {
|
|
385
|
+
typeInformation.staticAttributes.forEach((attr) => {
|
|
386
|
+
explicitAttrsList.push(attr.name);
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
} else if (typeInformation.explicitAttrs && typeof typeInformation.explicitAttrs === 'string') {
|
|
390
|
+
const attsArray = pluginUtils.extractAttributesArrayFromNgsi2Entity(result);
|
|
391
|
+
const ctx = jexlParser.extractContext(attsArray);
|
|
392
|
+
const res = jexlParser.applyExpression(typeInformation.explicitAttrs, ctx, typeInformation);
|
|
393
|
+
explicitAttrsList = res;
|
|
394
|
+
}
|
|
395
|
+
if (explicitAttrsList && explicitAttrsList.length >= 0) {
|
|
396
|
+
const hidden = _.difference(_.keys(result), explicitAttrsList);
|
|
397
|
+
logger.debug(context, 'removeHiddenAttrs %s', hidden);
|
|
398
|
+
hidden.forEach((attr) => {
|
|
399
|
+
delete result[attr];
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
return result;
|
|
403
|
+
}
|
|
404
|
+
|
|
315
405
|
/**
|
|
316
406
|
* Makes an update in the Device's entity in the context broker, with the values given in the 'attributes' array. This
|
|
317
407
|
* array should comply to the NGSIv2's attribute format.
|
|
@@ -326,7 +416,7 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca
|
|
|
326
416
|
|
|
327
417
|
let url = '/v2/entities/' + entityName + '/attrs';
|
|
328
418
|
|
|
329
|
-
if (typeInformation.type) {
|
|
419
|
+
if (typeInformation && typeInformation.type) {
|
|
330
420
|
url += '?type=' + typeInformation.type;
|
|
331
421
|
}
|
|
332
422
|
|
|
@@ -359,7 +449,6 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca
|
|
|
359
449
|
//overwritte if id or type missnamed atributes reach this point
|
|
360
450
|
payload.id = entityName;
|
|
361
451
|
payload.type = typeInformation.type;
|
|
362
|
-
|
|
363
452
|
payload = NGSIUtils.castJsonNativeAttributes(payload);
|
|
364
453
|
async.waterfall(
|
|
365
454
|
[
|
|
@@ -392,7 +481,7 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca
|
|
|
392
481
|
}
|
|
393
482
|
options.json = {
|
|
394
483
|
actionType: 'append',
|
|
395
|
-
entities: result
|
|
484
|
+
entities: removeHiddenAttrsFromMultiEntity(result, typeInformation)
|
|
396
485
|
};
|
|
397
486
|
if (config.getConfig().appendMode === true) {
|
|
398
487
|
options.json.actionType = 'append';
|
|
@@ -400,9 +489,7 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca
|
|
|
400
489
|
options.json.actionType = 'update';
|
|
401
490
|
}
|
|
402
491
|
} else {
|
|
403
|
-
|
|
404
|
-
delete result.type;
|
|
405
|
-
options.json = result;
|
|
492
|
+
options.json = removeHiddenAttrs(result, typeInformation);
|
|
406
493
|
logger.debug(context, 'typeInformation: %j', typeInformation);
|
|
407
494
|
if (
|
|
408
495
|
'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
|
}
|
|
@@ -176,7 +177,7 @@ function executeWithDeviceInformation(operationFunction) {
|
|
|
176
177
|
|
|
177
178
|
/**
|
|
178
179
|
* Update the result of a command in the Context Broker. The result of the command has two components: the result
|
|
179
|
-
* of the command itself will be represented with the sufix '
|
|
180
|
+
* of the command itself will be represented with the sufix '_info' in the entity while the status is updated in the
|
|
180
181
|
* attribute with the '_status' sufix.
|
|
181
182
|
*
|
|
182
183
|
* @param {String} entityName Name of the entity holding the command.
|
|
@@ -233,7 +234,7 @@ function setCommandResult(
|
|
|
233
234
|
}
|
|
234
235
|
|
|
235
236
|
if (commandInfo.length === 1) {
|
|
236
|
-
exports.update(entityName,
|
|
237
|
+
exports.update(entityName, typeInformation.type, apikey, attributes, typeInformation, callback);
|
|
237
238
|
} else {
|
|
238
239
|
callback(new errors.CommandNotFound(commandName));
|
|
239
240
|
}
|
|
@@ -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);
|
|
@@ -159,29 +159,32 @@ function generateUpdateActionsNgsi2(req, contextElement, callback) {
|
|
|
159
159
|
callback(null, updateActions);
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
-
deviceService.
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
deviceService.
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
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.
|
|
@@ -238,8 +241,7 @@ function defaultQueryHandlerNgsi2(id, type, service, subservice, attributes, cal
|
|
|
238
241
|
type,
|
|
239
242
|
id
|
|
240
243
|
};
|
|
241
|
-
|
|
242
|
-
deviceService.getDeviceByName(id, service, subservice, function (error, ngsiDevice) {
|
|
244
|
+
deviceService.getDeviceByNameAndType(id, type, service, subservice, function (error, ngsiDevice) {
|
|
243
245
|
if (error) {
|
|
244
246
|
callback(error);
|
|
245
247
|
} else {
|
|
@@ -285,8 +287,9 @@ function handleNotificationNgsi2(req, res, next) {
|
|
|
285
287
|
}
|
|
286
288
|
}
|
|
287
289
|
}
|
|
288
|
-
deviceService.
|
|
290
|
+
deviceService.getDeviceByNameAndType(
|
|
289
291
|
dataElement.id,
|
|
292
|
+
dataElement.type,
|
|
290
293
|
req.headers['fiware-service'],
|
|
291
294
|
req.headers['fiware-servicepath'],
|
|
292
295
|
function (error, device) {
|
|
@@ -448,6 +451,7 @@ function handleQueryNgsi2(req, res, next) {
|
|
|
448
451
|
}
|
|
449
452
|
|
|
450
453
|
deviceService.findConfigurationGroup(device, function (error, group) {
|
|
454
|
+
logger.debug(context, 'finishQueryForDevice %j', group);
|
|
451
455
|
const executeCompleteAttributes = apply(completeAttributes, attributes, group);
|
|
452
456
|
const executeQueryHandler = apply(
|
|
453
457
|
actualHandler,
|
|
@@ -474,8 +478,9 @@ function handleQueryNgsi2(req, res, next) {
|
|
|
474
478
|
|
|
475
479
|
if (contextEntity.id) {
|
|
476
480
|
getFunction = apply(
|
|
477
|
-
deviceService.
|
|
481
|
+
deviceService.getDeviceByNameAndType,
|
|
478
482
|
contextEntity.id,
|
|
483
|
+
contextEntity.type,
|
|
479
484
|
req.headers['fiware-service'],
|
|
480
485
|
req.headers['fiware-servicepath']
|
|
481
486
|
);
|
|
@@ -504,7 +509,7 @@ function handleQueryNgsi2(req, res, next) {
|
|
|
504
509
|
} else {
|
|
505
510
|
deviceList = [innerDevice];
|
|
506
511
|
}
|
|
507
|
-
|
|
512
|
+
logger.debug(context, 'handleFindDevice from %j', deviceList);
|
|
508
513
|
async.map(
|
|
509
514
|
deviceList,
|
|
510
515
|
async.apply(finishQueryForDevice, attributes, contextEntity, actualHandler),
|
|
@@ -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.
|
|
94
|
+
apply(ngsi.update, device.name, device.type, device.apikey, newAttributes, device)
|
|
95
95
|
);
|
|
96
96
|
}
|
|
97
97
|
}
|