iotagent-node-lib 3.3.0 → 3.4.1
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/CHANGES_NEXT_RELEASE +1 -0
- package/README.md +10 -11
- package/doc/README.md +16 -0
- package/doc/admin.md +565 -0
- package/doc/api.md +9 -5
- package/doc/deprecated.md +16 -14
- package/doc/{architecture.md → devel/architecture.md} +3 -3
- package/doc/{Contribution.md → devel/contribution-guidelines.md} +43 -35
- package/doc/devel/development.md +1879 -0
- package/doc/{northboundinteractions.md → devel/northboundinteractions.md} +18 -33
- package/doc/index.md +3 -5
- package/docker/Mosquitto/README.md +1 -0
- package/lib/commonConfig.js +0 -5
- package/lib/fiware-iotagent-lib.js +1 -1
- package/lib/jexlTranformsMap.js +2 -1
- package/lib/request-shim.js +2 -2
- package/lib/services/commands/commandService.js +1 -1
- package/lib/services/common/genericMiddleware.js +1 -1
- package/lib/services/devices/deviceRegistryMemory.js +2 -2
- package/lib/services/devices/deviceRegistryMongoDB.js +22 -9
- package/lib/services/devices/deviceService.js +36 -30
- package/lib/services/devices/devices-NGSI-LD.js +14 -2
- package/lib/services/devices/devices-NGSI-mixed.js +0 -2
- package/lib/services/devices/devices-NGSI-v2.js +22 -100
- package/lib/services/groups/groupService.js +1 -1
- package/lib/services/ngsi/entities-NGSI-v2.js +14 -27
- package/lib/services/northBound/deviceProvisioningServer.js +14 -5
- package/mkdocs.yml +6 -11
- package/package.json +3 -3
- package/scripts/legacy_expression_tool/README.md +56 -38
- package/test/unit/general/contextBrokerKeystoneSecurityAccess-test.js +2 -2
- package/test/unit/mongodb/mongodb-registry-test.js +1 -1
- package/test/unit/ngsi-ld/general/contextBrokerOAuthSecurityAccess-test.js +66 -65
- package/test/unit/ngsi-ld/general/https-support-test.js +1 -1
- package/test/unit/ngsi-ld/lazyAndCommands/command-test.js +8 -7
- package/test/unit/ngsi-ld/lazyAndCommands/polling-commands-test.js +12 -11
- package/test/unit/ngsi-ld/ngsiService/subscriptions-test.js +41 -39
- package/test/unit/ngsi-ld/provisioning/device-provisioning-api_test.js +122 -122
- package/test/unit/ngsi-ld/provisioning/device-registration_test.js +28 -28
- package/test/unit/ngsi-ld/provisioning/device-update-registration_test.js +18 -17
- package/test/unit/ngsi-ld/provisioning/singleConfigurationMode-test.js +7 -7
- package/test/unit/ngsi-ld/provisioning/updateProvisionedDevices-test.js +8 -7
- package/test/unit/ngsiv2/examples/contextRequests/updateContext6.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin1.json +0 -12
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin11.json +0 -4
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin12.json +1 -5
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin2.json +0 -12
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin29.json +0 -12
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin3.json +0 -4
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin41.json +0 -10
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin5.json +0 -4
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin6.json +0 -4
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin7.json +0 -4
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin8.json +0 -12
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin9.json +0 -4
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin25.json +1 -5
- package/test/unit/ngsiv2/expressions/jexlBasedTransformations-test.js +13 -12
- package/test/unit/ngsiv2/general/contextBrokerOAuthSecurityAccess-test.js +2 -2
- package/test/unit/ngsiv2/general/https-support-test.js +1 -1
- package/test/unit/ngsiv2/ngsiService/active-devices-test.js +3 -8
- package/test/unit/ngsiv2/ngsiService/subscriptions-test.js +10 -10
- package/test/unit/ngsiv2/provisioning/device-provisioning-api_test.js +8 -103
- package/test/unit/ngsiv2/provisioning/device-registration_test.js +8 -6
- package/test/unit/ngsiv2/provisioning/device-update-registration_test.js +2 -1
- package/test/unit/ngsiv2/provisioning/updateProvisionedDevices-test.js +0 -1
- package/.nyc_output/33364de2-1199-4ec2-b33c-cae063ef8cc4.json +0 -1
- package/.nyc_output/processinfo/33364de2-1199-4ec2-b33c-cae063ef8cc4.json +0 -1
- package/.nyc_output/processinfo/index.json +0 -1
- package/doc/config-basic-example.js +0 -20
- package/doc/development.md +0 -285
- package/doc/howto.md +0 -641
- package/doc/installationguide.md +0 -365
- package/doc/operations.md +0 -127
- package/doc/usermanual.md +0 -900
- package/lib/plugins/bidirectionalData.js +0 -356
- package/test/unit/ngsi-ld/plugins/bidirectional-plugin_test.js +0 -697
- package/test/unit/ngsiv2/plugins/bidirectional-plugin_test.js +0 -536
- /package/doc/{NorthboundInteractions.postman_collection → devel/NorthboundInteractions.postman_collection} +0 -0
- /package/doc/{echo.js → devel/echo.js} +0 -0
- /package/doc/{finalResult.js → devel/finalResult.js} +0 -0
|
@@ -61,46 +61,6 @@ function jsonConcat(json1, json2) {
|
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
/**
|
|
65
|
-
* Creates the response handler for the initial entity creation request using NGSIv2.
|
|
66
|
-
* This handler basically deals with the errors that could have been rised during
|
|
67
|
-
* the communication with the Context Broker.
|
|
68
|
-
*
|
|
69
|
-
* @param {Object} deviceData Object containing all the deviceData needed to send the registration.
|
|
70
|
-
* @param {Object} newDevice Device object that will be stored in the database.
|
|
71
|
-
* @return {function} Handler to pass to the request() function.
|
|
72
|
-
*/
|
|
73
|
-
function createInitialEntityHandlerNgsi2(deviceData, newDevice, callback) {
|
|
74
|
-
return function handleInitialEntityResponse(error, response, body) {
|
|
75
|
-
if (error) {
|
|
76
|
-
logger.error(
|
|
77
|
-
context,
|
|
78
|
-
'ORION-001: Connection error creating inital entity in the Context Broker: %s',
|
|
79
|
-
error
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
alarms.raise(constants.ORION_ALARM, error);
|
|
83
|
-
|
|
84
|
-
callback(error);
|
|
85
|
-
} else if (response && response.statusCode === 204) {
|
|
86
|
-
alarms.release(constants.ORION_ALARM);
|
|
87
|
-
logger.debug(context, 'Initial entity created successfully.');
|
|
88
|
-
callback(null, newDevice);
|
|
89
|
-
} else {
|
|
90
|
-
logger.error(
|
|
91
|
-
context,
|
|
92
|
-
'Protocol error connecting to the Context Broker [%d]: %s',
|
|
93
|
-
response.statusCode,
|
|
94
|
-
body
|
|
95
|
-
);
|
|
96
|
-
|
|
97
|
-
const errorObj = new errors.EntityGenericError(deviceData.id, deviceData.type, body, response.statusCode);
|
|
98
|
-
|
|
99
|
-
callback(errorObj);
|
|
100
|
-
}
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
|
|
104
64
|
/**
|
|
105
65
|
* Creates the response handler for the update entity request using NGSIv2. This handler basically deals with the errors
|
|
106
66
|
* that could have been rised during the communication with the Context Broker.
|
|
@@ -199,62 +159,12 @@ function formatCommandsNgsi2(originalVector) {
|
|
|
199
159
|
return attributeList;
|
|
200
160
|
}
|
|
201
161
|
|
|
202
|
-
|
|
203
|
-
*
|
|
204
|
-
*
|
|
205
|
-
*
|
|
206
|
-
* @param {Object} deviceData Object containing all the deviceData needed to send the registration.
|
|
207
|
-
* @param {Object} newDevice Device object that will be stored in the database.
|
|
162
|
+
/*
|
|
163
|
+
* This methods makes a bypass in updateRegisterDeviceNgsi2 to allow not change
|
|
164
|
+
* extractDeviceDifference and combineWithNewDevice methods
|
|
208
165
|
*/
|
|
209
|
-
function
|
|
210
|
-
|
|
211
|
-
url: config.getConfig().contextBroker.url + '/v2/entities?options=upsert',
|
|
212
|
-
method: 'POST',
|
|
213
|
-
json: {
|
|
214
|
-
id: String(deviceData.name),
|
|
215
|
-
type: deviceData.type
|
|
216
|
-
},
|
|
217
|
-
headers: {
|
|
218
|
-
'fiware-service': deviceData.service,
|
|
219
|
-
'fiware-servicepath': deviceData.subservice,
|
|
220
|
-
'fiware-correlator': (domain.active && domain.active.corr) || uuid.v4()
|
|
221
|
-
}
|
|
222
|
-
};
|
|
223
|
-
|
|
224
|
-
if (deviceData.cbHost && deviceData.cbHost.indexOf('://') !== -1) {
|
|
225
|
-
options.url = deviceData.cbHost + '/v2/entities?options=upsert';
|
|
226
|
-
} else if (deviceData.cbHost && deviceData.cbHost.indexOf('://') === -1) {
|
|
227
|
-
options.url = 'http://' + deviceData.cbHost + '/v2/entities?options=upsert';
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
jsonConcat(options.json, formatAttributesNgsi2(deviceData.active, false));
|
|
231
|
-
jsonConcat(options.json, formatAttributesNgsi2(deviceData.staticAttributes, true));
|
|
232
|
-
jsonConcat(options.json, formatCommandsNgsi2(deviceData.commands));
|
|
233
|
-
|
|
234
|
-
for (const att in options.json) {
|
|
235
|
-
try {
|
|
236
|
-
// Format any GeoJSON attrs properly
|
|
237
|
-
options.json[att] = NGSIv2.formatGeoAttrs(options.json[att]);
|
|
238
|
-
} catch (error) {
|
|
239
|
-
return callback(new errors.BadGeocoordinates(JSON.stringify(options.json)));
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
logger.debug(context, 'Creating initial entity with deviceData: %j', deviceData);
|
|
244
|
-
if (
|
|
245
|
-
('timestamp' in deviceData && deviceData.timestamp !== undefined
|
|
246
|
-
? deviceData.timestamp
|
|
247
|
-
: config.getConfig().timestamp) &&
|
|
248
|
-
!utils.isTimestampedNgsi2(options.json)
|
|
249
|
-
) {
|
|
250
|
-
logger.debug(context, 'config.timestamp %s %s', deviceData.timestamp, config.getConfig().timestamp);
|
|
251
|
-
options.json[constants.TIMESTAMP_ATTRIBUTE] = {
|
|
252
|
-
type: constants.TIMESTAMP_TYPE_NGSI2,
|
|
253
|
-
value: moment()
|
|
254
|
-
};
|
|
255
|
-
}
|
|
256
|
-
logger.debug(context, 'Creating initial entity in the Context Broker:\n %s', JSON.stringify(options, null, 4));
|
|
257
|
-
utils.executeWithSecurity(options, newDevice, createInitialEntityHandlerNgsi2(deviceData, newDevice, callback));
|
|
166
|
+
function createInitialEntityNgsi2Fake(deviceData, newDevice, callback) {
|
|
167
|
+
callback(null, newDevice);
|
|
258
168
|
}
|
|
259
169
|
|
|
260
170
|
/**
|
|
@@ -337,9 +247,10 @@ function updateRegisterDeviceNgsi2(deviceObj, entityInfoUpdated, callback) {
|
|
|
337
247
|
return;
|
|
338
248
|
}
|
|
339
249
|
|
|
340
|
-
logger.debug(context, 'Update provisioned v2 device in Device Service');
|
|
250
|
+
logger.debug(context, 'Update provisioned v2 device in Device Service %j %j', deviceObj, entityInfoUpdated);
|
|
341
251
|
|
|
342
252
|
function combineWithNewDevice(newDevice, oldDevice, callback) {
|
|
253
|
+
logger.debug(context, 'combineWithNewDevice %j %j', newDevice, oldDevice);
|
|
343
254
|
if (oldDevice) {
|
|
344
255
|
oldDevice.internalId = newDevice.internalId;
|
|
345
256
|
oldDevice.lazy = newDevice.lazy;
|
|
@@ -424,9 +335,15 @@ function updateRegisterDeviceNgsi2(deviceObj, entityInfoUpdated, callback) {
|
|
|
424
335
|
if (entityInfoUpdated) {
|
|
425
336
|
async.waterfall(
|
|
426
337
|
[
|
|
427
|
-
apply(
|
|
338
|
+
apply(
|
|
339
|
+
config.getRegistry().get,
|
|
340
|
+
deviceObj.id,
|
|
341
|
+
deviceObj.apikey,
|
|
342
|
+
deviceObj.service,
|
|
343
|
+
deviceObj.subservice
|
|
344
|
+
),
|
|
428
345
|
apply(extractDeviceDifference, deviceObj),
|
|
429
|
-
|
|
346
|
+
createInitialEntityNgsi2Fake,
|
|
430
347
|
apply(combineWithNewDevice, deviceObj),
|
|
431
348
|
apply(registrationUtils.sendRegistrations, false),
|
|
432
349
|
apply(registrationUtils.processContextRegistration, deviceObj),
|
|
@@ -437,7 +354,13 @@ function updateRegisterDeviceNgsi2(deviceObj, entityInfoUpdated, callback) {
|
|
|
437
354
|
} else {
|
|
438
355
|
async.waterfall(
|
|
439
356
|
[
|
|
440
|
-
apply(
|
|
357
|
+
apply(
|
|
358
|
+
config.getRegistry().get,
|
|
359
|
+
deviceObj.id,
|
|
360
|
+
deviceObj.apikey,
|
|
361
|
+
deviceObj.service,
|
|
362
|
+
deviceObj.subservice
|
|
363
|
+
),
|
|
441
364
|
apply(extractDeviceDifference, deviceObj),
|
|
442
365
|
updateEntityNgsi2,
|
|
443
366
|
apply(combineWithNewDevice, deviceObj),
|
|
@@ -450,7 +373,6 @@ function updateRegisterDeviceNgsi2(deviceObj, entityInfoUpdated, callback) {
|
|
|
450
373
|
}
|
|
451
374
|
}
|
|
452
375
|
|
|
453
|
-
exports.createInitialEntity = createInitialEntityNgsi2;
|
|
454
376
|
exports.updateRegisterDevice = updateRegisterDeviceNgsi2;
|
|
455
377
|
exports.formatCommands = formatCommandsNgsi2;
|
|
456
378
|
exports.formatAttributes = formatAttributesNgsi2;
|
|
@@ -172,7 +172,7 @@ function remove(service, subservice, resource, apikey, device, callback) {
|
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
function unregisterDevice(device, cb) {
|
|
175
|
-
deviceService.unregister(device.id, service, subservice, function (error) {
|
|
175
|
+
deviceService.unregister(device.id, device.apikey, service, subservice, function (error) {
|
|
176
176
|
if (error) {
|
|
177
177
|
cb(error);
|
|
178
178
|
}
|
|
@@ -354,11 +354,7 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca
|
|
|
354
354
|
payload.entities[0].type = typeInformation.type;
|
|
355
355
|
}
|
|
356
356
|
|
|
357
|
-
|
|
358
|
-
payload.actionType = 'update';
|
|
359
|
-
} else {
|
|
360
|
-
payload.actionType = 'append';
|
|
361
|
-
}
|
|
357
|
+
payload.actionType = 'append';
|
|
362
358
|
|
|
363
359
|
let options = NGSIUtils.createRequestObject(url, typeInformation, token);
|
|
364
360
|
|
|
@@ -680,8 +676,9 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca
|
|
|
680
676
|
try {
|
|
681
677
|
logger.debug(context, 'sendUpdateValueNgsi2 entityNameExp %j ', typeInformation.entityNameExp);
|
|
682
678
|
entityName = expressionPlugin.applyExpression(typeInformation.entityNameExp, ctxt, typeInformation);
|
|
683
|
-
|
|
684
|
-
|
|
679
|
+
// CB entity id should be always a String
|
|
680
|
+
payload.entities[0].id = String(entityName);
|
|
681
|
+
ctxt['entity_name'] = String(entityName);
|
|
685
682
|
} catch (e) {
|
|
686
683
|
logger.debug(
|
|
687
684
|
context,
|
|
@@ -762,9 +759,14 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca
|
|
|
762
759
|
if (expressionPlugin.contextAvailable(attr.expression, ctxt, typeInformation)) {
|
|
763
760
|
res = expressionPlugin.applyExpression(attr.expression, ctxt, typeInformation);
|
|
764
761
|
if (
|
|
765
|
-
// By default undefined is
|
|
766
|
-
(
|
|
767
|
-
|
|
762
|
+
// By default undefined is handled like null: should not progress
|
|
763
|
+
// Some op results (like nonexistent * 2) are a kind of null with a number type
|
|
764
|
+
// but NaN value
|
|
765
|
+
(attr.skipValue === undefined &&
|
|
766
|
+
(res === null || (typeof res === 'number' && isNaN(res)))) ||
|
|
767
|
+
(attr.skipValue !== undefined &&
|
|
768
|
+
(res === attr.skipValue ||
|
|
769
|
+
(typeof res === 'number' && isNaN(res) && attr.skipValue === null)))
|
|
768
770
|
) {
|
|
769
771
|
logger.debug(
|
|
770
772
|
context,
|
|
@@ -987,25 +989,10 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca
|
|
|
987
989
|
// only in the first case
|
|
988
990
|
if (options.json.entities.length === 1) {
|
|
989
991
|
// recreate options object to use single entity update
|
|
990
|
-
url = '/v2/entities';
|
|
991
|
-
if (config.getConfig().appendMode === false) {
|
|
992
|
-
url += '/' + entityName + '/attrs';
|
|
993
|
-
if (typeInformation && typeInformation.type) {
|
|
994
|
-
url += '?type=' + typeInformation.type;
|
|
995
|
-
}
|
|
996
|
-
} else {
|
|
997
|
-
// appendMode === true
|
|
998
|
-
url += '?options=upsert';
|
|
999
|
-
}
|
|
992
|
+
url = '/v2/entities?options=upsert';
|
|
1000
993
|
options = NGSIUtils.createRequestObject(url, typeInformation, token);
|
|
1001
994
|
options.json = payload.entities[0];
|
|
1002
|
-
|
|
1003
|
-
options.method = 'PATCH';
|
|
1004
|
-
delete options.json.id;
|
|
1005
|
-
delete options.json.type;
|
|
1006
|
-
} else {
|
|
1007
|
-
options.method = 'POST';
|
|
1008
|
-
}
|
|
995
|
+
options.method = 'POST';
|
|
1009
996
|
} // else: keep current options object created for a batch update
|
|
1010
997
|
logger.debug(context, 'Updating device value in the Context Broker at [%s]', options.url);
|
|
1011
998
|
logger.debug(context, 'Using the following NGSI v2 request:\n\n%s\n\n', JSON.stringify(options, null, 4));
|
|
@@ -251,6 +251,7 @@ function handleListDevices(req, res, next) {
|
|
|
251
251
|
function handleGetDevice(req, res, next) {
|
|
252
252
|
deviceService.getDevice(
|
|
253
253
|
req.params.deviceId,
|
|
254
|
+
req.query.apikey,
|
|
254
255
|
req.headers['fiware-service'],
|
|
255
256
|
req.headers['fiware-servicepath'],
|
|
256
257
|
function (error, device) {
|
|
@@ -269,8 +270,8 @@ function handleGetDevice(req, res, next) {
|
|
|
269
270
|
* This middleware handles the removal of a particular device specified with the deviceId.
|
|
270
271
|
*/
|
|
271
272
|
function handleRemoveDevice(req, res, next) {
|
|
272
|
-
function getDevice(deviceId, service, subservice, callback) {
|
|
273
|
-
deviceService.getDevice(deviceId, service, subservice, function (error, device) {
|
|
273
|
+
function getDevice(deviceId, apikey, service, subservice, callback) {
|
|
274
|
+
deviceService.getDevice(deviceId, apikey, service, subservice, function (error, device) {
|
|
274
275
|
if (error) {
|
|
275
276
|
callback(error);
|
|
276
277
|
} else if (device) {
|
|
@@ -289,18 +290,25 @@ function handleRemoveDevice(req, res, next) {
|
|
|
289
290
|
}
|
|
290
291
|
}
|
|
291
292
|
|
|
292
|
-
function unregisterDevice(deviceId, service, subservice, device, callback) {
|
|
293
|
-
return deviceService.unregister(deviceId, service, subservice, callback);
|
|
293
|
+
function unregisterDevice(deviceId, apikey, service, subservice, device, callback) {
|
|
294
|
+
return deviceService.unregister(deviceId, apikey, service, subservice, callback);
|
|
294
295
|
}
|
|
295
296
|
|
|
296
297
|
async.waterfall(
|
|
297
298
|
[
|
|
298
299
|
apply(statsRegistry.add, 'deviceRemovalRequests', 1),
|
|
299
|
-
apply(
|
|
300
|
+
apply(
|
|
301
|
+
getDevice,
|
|
302
|
+
req.params.deviceId,
|
|
303
|
+
req.query.apikey,
|
|
304
|
+
req.headers['fiware-service'],
|
|
305
|
+
req.headers['fiware-servicepath']
|
|
306
|
+
),
|
|
300
307
|
applyRemoveDeviceHandler,
|
|
301
308
|
apply(
|
|
302
309
|
unregisterDevice,
|
|
303
310
|
req.params.deviceId,
|
|
311
|
+
req.query.apikey,
|
|
304
312
|
req.headers['fiware-service'],
|
|
305
313
|
req.headers['fiware-servicepath']
|
|
306
314
|
)
|
|
@@ -334,6 +342,7 @@ function handleUpdateDevice(req, res, next) {
|
|
|
334
342
|
} else {
|
|
335
343
|
deviceService.getDevice(
|
|
336
344
|
req.params.deviceId,
|
|
345
|
+
req.query.apikey,
|
|
337
346
|
req.headers['fiware-service'],
|
|
338
347
|
req.headers['fiware-servicepath'],
|
|
339
348
|
function (error, device) {
|
package/mkdocs.yml
CHANGED
|
@@ -13,15 +13,10 @@ pages:
|
|
|
13
13
|
- Home: 'index.md'
|
|
14
14
|
- 'Getting Started' : 'getting-started.md'
|
|
15
15
|
- 'User & Programmers Manual':
|
|
16
|
-
- 'Architecture' : 'architecture.md'
|
|
17
16
|
- 'IoT Agent API' : 'api.md'
|
|
18
|
-
- '
|
|
19
|
-
|
|
20
|
-
- '
|
|
21
|
-
- '
|
|
22
|
-
- '
|
|
23
|
-
- '
|
|
24
|
-
- 'Installation & Administration Manual':
|
|
25
|
-
- 'Installation Guide': 'installationguide.md'
|
|
26
|
-
- 'Operations (logs & alarms)': 'operations.md'
|
|
27
|
-
|
|
17
|
+
- 'Installation and administration manual': 'admin.md'
|
|
18
|
+
- 'Development documentation':
|
|
19
|
+
- 'Development manual': 'devel/development.md'
|
|
20
|
+
- 'Contributing guide': 'devel/contribution-guidelines.md'
|
|
21
|
+
- 'Architecture' : 'devel/architecture.md'
|
|
22
|
+
- 'North Port - NGSI Interactions': 'devel/northboundinteractions.md'
|
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": "3.
|
|
5
|
+
"version": "3.4.1",
|
|
6
6
|
"homepage": "https://github.com/telefonicaid/iotagent-node-lib",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"fiware",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"logops": "2.1.2",
|
|
52
52
|
"moment": "~2.29.2",
|
|
53
53
|
"moment-timezone": "~0.5.34",
|
|
54
|
-
"mongoose": "5.13.
|
|
54
|
+
"mongoose": "5.13.20",
|
|
55
55
|
"query-string": "7.1.1",
|
|
56
56
|
"revalidator": "~0.3.1",
|
|
57
57
|
"underscore": "~1.13.4",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"husky": "~4.2.5",
|
|
66
66
|
"lint-staged": "~12.3.8",
|
|
67
67
|
"mocha": "10.0.0",
|
|
68
|
-
"mongodb": "4.
|
|
68
|
+
"mongodb": "4.17.0",
|
|
69
69
|
"nock": "13.2.7",
|
|
70
70
|
"nyc": "~15.1.0",
|
|
71
71
|
"prettier": "~2.7.1",
|
|
@@ -82,34 +82,50 @@ python legacy_expression_tool.py \
|
|
|
82
82
|
|
|
83
83
|
The list of possible arguments that the scripts accepts are:
|
|
84
84
|
|
|
85
|
-
| Argument | Description
|
|
86
|
-
| ---------------------- |
|
|
87
|
-
| `--mongouri` | The MongoDB URI to connect to
|
|
88
|
-
| `--database` | The database name to replace the expressions
|
|
89
|
-
| `--collection` | The collection name to replace the expressions
|
|
90
|
-
| `--translation` | The translation dictionary file to replace the expressions
|
|
91
|
-
| `--debug` | Enable debug mode
|
|
92
|
-
| `--commit` | Commit the changes to the database
|
|
85
|
+
| Argument | Description | Default value | Mandatory |
|
|
86
|
+
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- | --------- |
|
|
87
|
+
| `--mongouri` | The MongoDB URI to connect to | `mongodb://localhost:27017/` | No |
|
|
88
|
+
| `--database` | The database name to replace the expressions | NA | Yes |
|
|
89
|
+
| `--collection` | The collection name to replace the expressions | NA | Yes |
|
|
90
|
+
| `--translation` | The translation dictionary file to replace the expressions | `translation.json` | No |
|
|
91
|
+
| `--debug` | Enable debug mode | `False` | No |
|
|
92
|
+
| `--commit` | Commit the changes to the database | `False` | No |
|
|
93
93
|
| `--expressionlanguage` | What to do with the expression language field. Possibles values: `delete`, `ignore`, `jexl` or `jexlall`. More detail on this bellow. | `ignore` | No |
|
|
94
|
-
| `--statistics` | Print match statistics. Aggregation modes are the possible values: `service` and `subservice`
|
|
95
|
-
| `--service` | The fiware service filter to replace the expressions
|
|
96
|
-
| `--service-path` | The fiware service path filter to replace the expressions
|
|
97
|
-
| `--deviceid` | The device id filter to replace the expressions
|
|
98
|
-
| `--entitytype` | The entity type filter to replace the expressions
|
|
99
|
-
| `--regexservice` | The fiware service regex filter to replace the expressions
|
|
100
|
-
| `--regexservicepath` | The fiware service path regex filter to replace the expressions
|
|
101
|
-
| `--regexdeviceid` | The device id regex filter to replace the expressions
|
|
102
|
-
| `--regexentitytype` | The entity type regex filter to replace the expressions
|
|
94
|
+
| `--statistics` | Print match statistics. Aggregation modes are the possible values: `service` and `subservice` | `service` | No |
|
|
95
|
+
| `--service` | The fiware service filter to replace the expressions | All subservices | No |
|
|
96
|
+
| `--service-path` | The fiware service path filter to replace the expressions | All subservices | No |
|
|
97
|
+
| `--deviceid` | The device id filter to replace the expressions | All devices | No |
|
|
98
|
+
| `--entitytype` | The entity type filter to replace the expressions | All entity types | No |
|
|
99
|
+
| `--regexservice` | The fiware service regex filter to replace the expressions | All subservices | No |
|
|
100
|
+
| `--regexservicepath` | The fiware service path regex filter to replace the expressions | All subservices | No |
|
|
101
|
+
| `--regexdeviceid` | The device id regex filter to replace the expressions | All devices | No |
|
|
102
|
+
| `--regexentitytype` | The entity type regex filter to replace the expressions | All entity types | No |
|
|
103
103
|
|
|
104
104
|
Note that filters (`--service`, `--service-path`, `--deviceid` and `--entitytype`, and the regex versions) are
|
|
105
105
|
interpreted in additive way (i.e. like a logical AND).
|
|
106
106
|
|
|
107
107
|
With regards to `--expressionlanguage`:
|
|
108
108
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
109
|
+
- `delete`: changes expressions from legacy to JEXL equivalence in the
|
|
110
|
+
[fields where expressions may be used](#fields-in-which-expressions-may-be-used) (based on the translation
|
|
111
|
+
dictionary specified by `--translations`). In addition, deletes the `expressionLanguage` field (no matter its value)
|
|
112
|
+
in the case it exists in the group/device.
|
|
113
|
+
- `ignore`: changes expressions from legacy to JEXL equivalence in the
|
|
114
|
+
[fields where expressions may be used](#fields-in-which-expressions-may-be-used) (based on the translation
|
|
115
|
+
dictionary specified by `--translations`). In addition, it leaves untouched the `expressionLanguage` field. This may
|
|
116
|
+
cause inconsistencies, if the value of the `expressionLanguage` is `legacy`, as detailed
|
|
117
|
+
[in this section](#replacing-expression-without-setting-jexl-at-group-or-device-level).
|
|
118
|
+
- `jexl`: changes expressions from legacy to JEXL equivalence in the
|
|
119
|
+
[fields where expressions may be used](#fields-in-which-expressions-may-be-used) (based on the translation
|
|
120
|
+
dictionary specified by `--translations`). In addition, it set `expressionLanguage` field to `jexl` (no matter if
|
|
121
|
+
the field originally exists in the group/device or not) **if some JEXL expression were translated**.
|
|
122
|
+
- `jexlall`: changes expression from legacy to JEXL equivalence in the
|
|
123
|
+
[fields where expressions may be used](#fields-in-which-expressions-may-be-used) (based on the translation
|
|
124
|
+
dictionary specified by `--translations`). In addition, it set `expressionLanguage` field to `jexl` (no matter if
|
|
125
|
+
the field originally exists in the group/device or not). The difference between `jexl`and `jexlall` is in the second
|
|
126
|
+
case, the script is not only looking for documents that contains legacy expressions, it also includes all
|
|
127
|
+
groups/devices that have `expressionLanguage` field defined. The `expressionLanguage` field on those documents (and
|
|
128
|
+
also on the documents that contains legacy expresions) is set to `jexl`.
|
|
113
129
|
|
|
114
130
|
## Usage
|
|
115
131
|
|
|
@@ -231,32 +247,34 @@ All 1 1 2
|
|
|
231
247
|
|
|
232
248
|
The script implements expression detection and translation in the following fields in group/device documents at DB:
|
|
233
249
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
250
|
+
- active.expression
|
|
251
|
+
- active.entity_name
|
|
252
|
+
- active.reverse
|
|
253
|
+
- attributes.expression
|
|
254
|
+
- attributes.entity_name
|
|
255
|
+
- attributes.expression
|
|
256
|
+
- commands.expression
|
|
257
|
+
- endpoint
|
|
258
|
+
- entityNameExp
|
|
259
|
+
- explicitAttrs
|
|
244
260
|
|
|
245
261
|
### Known issues
|
|
246
262
|
|
|
247
263
|
#### Execution with `expressionlanguage` set to `jexlall`
|
|
248
264
|
|
|
249
265
|
When executing the script with `expressionlanguage` set to `jexlall`, the script will look for all the documents
|
|
250
|
-
containing legacy expressions (in some of the [expression capable fields](#fields-in-which-expressions-may-be-used)) or
|
|
251
|
-
This would change the number of documents found, and the statistics
|
|
266
|
+
containing legacy expressions (in some of the [expression capable fields](#fields-in-which-expressions-may-be-used)) or
|
|
267
|
+
the existence of the `expressionLanguage` field. This would change the number of documents found, and the statistics
|
|
268
|
+
will include extra documents.
|
|
252
269
|
|
|
253
270
|
Running the script with the option set to `jexl` would not include such extra documents in statistics.
|
|
254
271
|
|
|
255
272
|
#### Replacing expression without setting jexl at group or device level
|
|
256
273
|
|
|
257
|
-
When executing the script setting `--expressionlanguage` to `ignore` (or when `--expressionlanguage` is not used), the
|
|
258
|
-
change the`expressionLanguage` field in the document. This means that the legacy expressions will be
|
|
259
|
-
`expressionLanguage` field will still be set to the default value or legacy. This would make
|
|
260
|
-
fail, propagating the value of the attribute as the expression literal to the context broker.
|
|
274
|
+
When executing the script setting `--expressionlanguage` to `ignore` (or when `--expressionlanguage` is not used), the
|
|
275
|
+
script will not change the`expressionLanguage` field in the document. This means that the legacy expressions will be
|
|
276
|
+
replaced, but the `expressionLanguage` field will still be set to the default value or legacy. This would make
|
|
277
|
+
expression evaluation to fail, propagating the value of the attribute as the expression literal to the context broker.
|
|
261
278
|
|
|
262
|
-
To avoid this, it is recommended use always the `--expressionlangauge` parameter set to `jexl`, so doing it a value
|
|
279
|
+
To avoid this, it is recommended use always the `--expressionlangauge` parameter set to `jexl`, so doing it a value
|
|
280
|
+
different from `ignore` will be used.
|
|
@@ -293,7 +293,7 @@ describe('NGSI-v2 - Secured access to the Context Broker with Keystone', functio
|
|
|
293
293
|
});
|
|
294
294
|
|
|
295
295
|
it('subscribe requests use auth header', function (done) {
|
|
296
|
-
iotAgentLib.getDevice('Light1', 'smartgondor', 'electricity', function (error, device) {
|
|
296
|
+
iotAgentLib.getDevice('Light1', null, 'smartgondor', 'electricity', function (error, device) {
|
|
297
297
|
iotAgentLib.subscribe(device, ['dimming'], null, function (error) {
|
|
298
298
|
should.not.exist(error);
|
|
299
299
|
|
|
@@ -314,7 +314,7 @@ describe('NGSI-v2 - Secured access to the Context Broker with Keystone', functio
|
|
|
314
314
|
'X-Subject-Token': '12345679ABCDEF'
|
|
315
315
|
});
|
|
316
316
|
|
|
317
|
-
iotAgentLib.getDevice('Light1', 'smartgondor', 'electricity', function (error, device) {
|
|
317
|
+
iotAgentLib.getDevice('Light1', null, 'smartgondor', 'electricity', function (error, device) {
|
|
318
318
|
iotAgentLib.subscribe(device, ['dimming'], null, function (error) {
|
|
319
319
|
iotAgentLib.unsubscribe(device, '51c0ac9ed714fb3b37d7d5a8', function (error) {
|
|
320
320
|
contextBrokerMock.done();
|
|
@@ -387,7 +387,7 @@ describe('NGSI-v2 - MongoDB Device Registry', function () {
|
|
|
387
387
|
});
|
|
388
388
|
|
|
389
389
|
it('should be removed from MongoDB', function (done) {
|
|
390
|
-
iotAgentLib.unregister(device1.id, 'smartgondor', 'gardens', function (error) {
|
|
390
|
+
iotAgentLib.unregister(device1.id, null, 'smartgondor', 'gardens', function (error) {
|
|
391
391
|
iotAgentDb
|
|
392
392
|
.db()
|
|
393
393
|
.collection('devices')
|