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