iotagent-node-lib 4.8.0 → 4.10.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 +10 -9
- package/.nyc_output/e4b1fe20-197e-4221-9f8d-6db65ff234b2.json +1 -0
- package/.nyc_output/processinfo/e4b1fe20-197e-4221-9f8d-6db65ff234b2.json +1 -0
- package/.nyc_output/processinfo/index.json +1 -0
- package/Changelog +791 -0
- package/config.js +2 -1
- package/doc/admin.md +20 -4
- package/doc/api.md +34 -4
- package/doc/devel/northboundinteractions.md +200 -112
- package/lib/commonConfig.js +16 -3
- package/lib/model/Device.js +3 -1
- package/lib/model/Group.js +2 -1
- package/lib/services/common/domain.js +4 -3
- package/lib/services/common/iotManagerService.js +2 -1
- package/lib/services/devices/deviceRegistryMongoDB.js +5 -1
- package/lib/services/devices/deviceService.js +17 -1
- package/lib/services/devices/devices-NGSI-LD.js +4 -4
- package/lib/services/devices/devices-NGSI-mixed.js +16 -0
- package/lib/services/devices/devices-NGSI-v2.js +123 -10
- package/lib/services/devices/registrationUtils.js +97 -30
- package/lib/services/groups/groupRegistryMongoDB.js +2 -1
- package/lib/services/ngsi/entities-NGSI-LD.js +69 -13
- package/lib/services/ngsi/ngsiService.js +3 -1
- package/lib/services/ngsi/subscription-NGSI-LD.js +2 -2
- package/lib/services/ngsi/subscription-NGSI-mixed.js +3 -3
- package/lib/services/ngsi/subscription-NGSI-v2.js +20 -6
- package/lib/services/ngsi/subscriptionService.js +2 -2
- package/lib/services/northBound/contextServer-NGSI-LD.js +5 -3
- package/lib/services/northBound/deviceProvisioningServer.js +6 -3
- package/lib/services/northBound/northboundServer.js +1 -1
- package/lib/services/northBound/restUtils.js +6 -2
- package/lib/templates/updateDevice.json +12 -0
- package/lib/templates/updateDeviceLax.json +4 -0
- package/package.json +2 -2
- package/test/functional/config-test.js +1 -1
- package/test/unit/general/contextBrokerKeystoneSecurityAccess-test.js +2 -2
- package/test/unit/memoryRegistry/deviceRegistryMemory_test.js +1 -1
- package/test/unit/ngsi-ld/examples/contextRequests/createDatetimeProvisionedDevice.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDevice.json +3 -12
- package/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDeviceMultientity.json +3 -12
- package/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDeviceWithGroupAndStatic.json +6 -24
- package/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDeviceWithGroupAndStatic2.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContext1.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContext3WithStatic.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContext4.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContext5.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin6.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin7.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin8.json +4 -2
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin9.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextCommandError.json +3 -9
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextCommandExpired.json +13 -19
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextCommandFinish.json +13 -19
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextCommandStatus1.json +4 -9
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextCompressTimestamp1.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextCompressTimestamp2.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin1a.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin2.json +2 -8
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin29.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin4.json +2 -8
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin4a.json +3 -12
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin6.json +3 -5
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin7.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin8a.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextJsonProperty.json +13 -0
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextListProperty.json +14 -0
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextListRelationship.json +14 -0
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin1.json +2 -8
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin2.json +2 -8
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin3.json +3 -8
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin4.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin5.json +2 -8
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin8.json +2 -8
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityTimestampPlugin1.json +2 -8
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityTimestampPlugin2.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityTimestampPlugin3.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityTimestampPlugin4.json +2 -8
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextRelationship.json +11 -0
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextValueType1.json +51 -0
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextValueType2.json +65 -0
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextVocabProperty.json +11 -0
- package/test/unit/ngsi-ld/examples/contextRequests/updateProvisionCommands1.json +2 -8
- package/test/unit/ngsi-ld/examples/contextRequests/updateProvisionDeviceStatic.json +1 -4
- package/test/unit/ngsi-ld/general/contextBrokerOAuthSecurityAccess-test.js +2 -2
- package/test/unit/ngsi-ld/general/https-support-test.js +1 -1
- package/test/unit/ngsi-ld/general/startup-test.js +3 -0
- package/test/unit/ngsi-ld/lazyAndCommands/command-test.js +1 -1
- package/test/unit/ngsi-ld/lazyAndCommands/lazy-devices-test.js +71 -1
- package/test/unit/ngsi-ld/ngsiService/attributeTypes-test.js +293 -0
- package/test/unit/ngsi-ld/ngsiService/subscriptions-test.js +6 -6
- package/test/unit/ngsi-ld/ngsiService/unsupported-endpoints-test.js +0 -10
- package/test/unit/ngsi-ld/ngsiService/value-types-test.js +221 -0
- package/test/unit/ngsiv2/examples/contextAvailabilityRequests/subscribeIoTAgentCommands.json +24 -0
- package/test/unit/ngsiv2/examples/contextAvailabilityRequests/subscribeIoTAgentCommands2.json +24 -0
- package/test/unit/ngsiv2/examples/contextAvailabilityRequests/subscribeIoTAgentCommands3.json +24 -0
- package/test/unit/ngsiv2/examples/contextAvailabilityRequests/subscribeIoTAgentCommands4.json +24 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateEntity.json +5 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateEntity2.json +5 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateEntity2b.json +7 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateEntity3.json +5 -0
- package/test/unit/ngsiv2/examples/subscriptionRequests/simpleSubscriptionRequest.json +4 -2
- package/test/unit/ngsiv2/examples/subscriptionRequests/simpleSubscriptionRequest2.json +4 -2
- 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/lazyAndCommands/command-test.js +245 -2
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast1.json +0 -11
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast10.json +0 -14
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast2.json +0 -11
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast3.json +0 -11
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast4.json +0 -11
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast5.json +0 -7
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast6.json +0 -17
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast7.json +0 -19
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast8.json +0 -14
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast9.json +0 -14
- package/test/unit/ngsi-ld/ngsiService/languageProperties-test.js +0 -109
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast1.json +0 -8
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast2.json +0 -8
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast3.json +0 -8
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast4.json +0 -8
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast5.json +0 -8
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast6.json +0 -8
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast7.json +0 -8
- /package/test/unit/ngsi-ld/examples/contextRequests/{updateContextLanguageProperties1.json → updateContextLanguageProperty.json} +0 -0
package/lib/commonConfig.js
CHANGED
|
@@ -157,9 +157,11 @@ function processEnvironmentVariables() {
|
|
|
157
157
|
'IOTA_FALLBACK_PATH',
|
|
158
158
|
'IOTA_LD_SUPPORT_NULL',
|
|
159
159
|
'IOTA_LD_SUPPORT_DATASET_ID',
|
|
160
|
+
'IOTA_LD_SUPPORT_DATA_TYPE',
|
|
160
161
|
'IOTA_EXPRESS_LIMIT',
|
|
161
162
|
'IOTA_USE_CB_FLOW_CONTROL',
|
|
162
|
-
'IOTA_STORE_LAST_MEASURE'
|
|
163
|
+
'IOTA_STORE_LAST_MEASURE',
|
|
164
|
+
'IOTA_CMD_MODE'
|
|
163
165
|
];
|
|
164
166
|
const iotamVariables = [
|
|
165
167
|
'IOTA_IOTAM_URL',
|
|
@@ -264,7 +266,12 @@ function processEnvironmentVariables() {
|
|
|
264
266
|
config.server.port = process.env.IOTA_NORTH_PORT;
|
|
265
267
|
}
|
|
266
268
|
|
|
267
|
-
config.server.ldSupport = config.server.ldSupport || {
|
|
269
|
+
config.server.ldSupport = config.server.ldSupport || {
|
|
270
|
+
null: true,
|
|
271
|
+
datasetId: true,
|
|
272
|
+
merge: false,
|
|
273
|
+
dataType: 'none'
|
|
274
|
+
};
|
|
268
275
|
|
|
269
276
|
if (process.env.IOTA_LD_SUPPORT_NULL) {
|
|
270
277
|
config.server.ldSupport.null = process.env.IOTA_LD_SUPPORT_NULL === 'true';
|
|
@@ -275,6 +282,9 @@ function processEnvironmentVariables() {
|
|
|
275
282
|
if (process.env.IOTA_LD_SUPPORT_MERGE) {
|
|
276
283
|
config.server.ldSupport.datasetId = process.env.IOTA_LD_SUPPORT_MERGE === 'true';
|
|
277
284
|
}
|
|
285
|
+
if (process.env.IOTA_LD_SUPPORT_DATA_TYPE) {
|
|
286
|
+
config.server.ldSupport.dataType = process.env.IOTA_LD_SUPPORT_DATA_TYPE;
|
|
287
|
+
}
|
|
278
288
|
|
|
279
289
|
if (process.env.IOTA_PROVIDER_URL) {
|
|
280
290
|
config.providerUrl = process.env.IOTA_PROVIDER_URL;
|
|
@@ -491,6 +501,9 @@ function processEnvironmentVariables() {
|
|
|
491
501
|
} else {
|
|
492
502
|
config.storeLastMeasure = config.storeLastMeasure === true;
|
|
493
503
|
}
|
|
504
|
+
if (process.env.IOTA_CMD_MODE) {
|
|
505
|
+
config.cmdMode = process.env.IOTA_CMD_MODE;
|
|
506
|
+
}
|
|
494
507
|
}
|
|
495
508
|
|
|
496
509
|
function setConfig(newConfig) {
|
|
@@ -511,7 +524,7 @@ function getConfig() {
|
|
|
511
524
|
function getConfigForTypeInformation() {
|
|
512
525
|
// Just return relevant configuration flags
|
|
513
526
|
// avoid to include server, authentication, mongodb, orion and iotamanger info
|
|
514
|
-
|
|
527
|
+
const conf = {
|
|
515
528
|
timestamp: config.timestamp,
|
|
516
529
|
defaultResource: config.defaultResource,
|
|
517
530
|
explicitAttrs: config.explicitAttrs,
|
package/lib/model/Device.js
CHANGED
package/lib/model/Group.js
CHANGED
|
@@ -68,7 +68,7 @@ function requestDomain(req, res, next) {
|
|
|
68
68
|
reqDomain.path = req.path;
|
|
69
69
|
reqDomain.op = req.url;
|
|
70
70
|
reqDomain.start = Date.now();
|
|
71
|
-
|
|
71
|
+
reqDomain.from = req.ip || req.connection.remoteAddress;
|
|
72
72
|
reqDomain.add(req);
|
|
73
73
|
reqDomain.add(res);
|
|
74
74
|
|
|
@@ -145,14 +145,15 @@ function ensureSouthboundTransaction(context, callback) {
|
|
|
145
145
|
if (context.op) {
|
|
146
146
|
reqDomain.op = context.op;
|
|
147
147
|
}
|
|
148
|
-
|
|
149
148
|
if (context.srv) {
|
|
150
149
|
reqDomain.service = context.srv;
|
|
151
150
|
}
|
|
152
|
-
|
|
153
151
|
if (context.subsrv) {
|
|
154
152
|
reqDomain.subservice = context.subsrv;
|
|
155
153
|
}
|
|
154
|
+
if (context.from) {
|
|
155
|
+
reqDomain.from = context.from;
|
|
156
|
+
}
|
|
156
157
|
}
|
|
157
158
|
|
|
158
159
|
return reqDomain.run(callback);
|
|
@@ -65,7 +65,8 @@ function register(callback) {
|
|
|
65
65
|
endpoint: service.endpoint,
|
|
66
66
|
transport: service.transport,
|
|
67
67
|
useCBflowControl: service.useCBflowControl,
|
|
68
|
-
storeLastMeasure: service.storeLastMeasure
|
|
68
|
+
storeLastMeasure: service.storeLastMeasure,
|
|
69
|
+
cmdMode: service.cmdMode
|
|
69
70
|
};
|
|
70
71
|
}
|
|
71
72
|
|
|
@@ -59,7 +59,9 @@ const attributeList = [
|
|
|
59
59
|
'subscriptions',
|
|
60
60
|
'payloadType',
|
|
61
61
|
'useCBflowControl',
|
|
62
|
-
'storeLastMeasure'
|
|
62
|
+
'storeLastMeasure',
|
|
63
|
+
'cmdMode',
|
|
64
|
+
'subscriptionId'
|
|
63
65
|
];
|
|
64
66
|
|
|
65
67
|
/**
|
|
@@ -324,6 +326,8 @@ function update(previousDevice, device, callback) {
|
|
|
324
326
|
data.useCBflowControl = device.useCBflowControl;
|
|
325
327
|
data.storeLastMeasure = device.storeLastMeasure;
|
|
326
328
|
data.lastMeasure = device.lastMeasure;
|
|
329
|
+
data.cmdMode = device.cmdMode;
|
|
330
|
+
data.subscriptionId = device.subscriptionId;
|
|
327
331
|
|
|
328
332
|
/* eslint-disable-next-line new-cap */
|
|
329
333
|
const deviceObj = new Device.model(data);
|
|
@@ -66,6 +66,17 @@ function init() {
|
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Creates the initial entity representing the device in the Context Broker. This is important mainly to allow the
|
|
71
|
+
* rest of the updateContext operations to be performed using an UPDATE action instead of an APPEND one.
|
|
72
|
+
*
|
|
73
|
+
* @param {Object} deviceData Object containing all the deviceData needed to send the registration.
|
|
74
|
+
* @param {Object} newDevice Device object that will be stored in the database.
|
|
75
|
+
*/
|
|
76
|
+
function createInitialEntity(deviceData, newDevice, callback) {
|
|
77
|
+
deviceHandler.createInitialEntity(deviceData, newDevice, callback);
|
|
78
|
+
}
|
|
79
|
+
|
|
69
80
|
/**
|
|
70
81
|
* If the object_id or the name of the attribute is missing, complete it with the other piece of data.
|
|
71
82
|
*
|
|
@@ -187,6 +198,9 @@ function mergeDeviceWithConfiguration(fields, defaults, deviceData, configuratio
|
|
|
187
198
|
if (configuration && configuration.storeLastMeasure !== undefined && deviceData.storeLastMeasure === undefined) {
|
|
188
199
|
deviceData.storeLastMeasure = configuration.storeLastMeasure;
|
|
189
200
|
}
|
|
201
|
+
if (configuration && configuration.cmdMode !== undefined && deviceData.cmdMode === undefined) {
|
|
202
|
+
deviceData.cmdMode = configuration.cmdMode;
|
|
203
|
+
}
|
|
190
204
|
logger.debug(context, 'deviceData after merge with conf: %j', deviceData);
|
|
191
205
|
callback(null, deviceData);
|
|
192
206
|
}
|
|
@@ -361,13 +375,15 @@ function registerDevice(deviceObj, callback) {
|
|
|
361
375
|
async.waterfall(
|
|
362
376
|
[
|
|
363
377
|
apply(registrationUtils.sendRegistrations, false, deviceData),
|
|
364
|
-
apply(registrationUtils.processContextRegistration, deviceData)
|
|
378
|
+
apply(registrationUtils.processContextRegistration, deviceData),
|
|
379
|
+
apply(createInitialEntity, deviceData)
|
|
365
380
|
],
|
|
366
381
|
function (error, results) {
|
|
367
382
|
if (error) {
|
|
368
383
|
callback(error);
|
|
369
384
|
} else {
|
|
370
385
|
deviceObj.registrationId = results.registrationId;
|
|
386
|
+
deviceObj.subscriptionId = results.subscriptionId;
|
|
371
387
|
deviceObj.name = deviceData.name;
|
|
372
388
|
deviceObj.service = deviceData.service;
|
|
373
389
|
deviceObj.subservice = deviceData.subservice;
|
|
@@ -33,7 +33,6 @@ const logger = require('logops');
|
|
|
33
33
|
const config = require('../../commonConfig');
|
|
34
34
|
const ngsiLD = require('../ngsi/entities-NGSI-LD');
|
|
35
35
|
const utils = require('../northBound/restUtils');
|
|
36
|
-
const moment = require('moment');
|
|
37
36
|
const _ = require('underscore');
|
|
38
37
|
const registrationUtils = require('./registrationUtils');
|
|
39
38
|
const NGSIv2 = require('./devices-NGSI-v2');
|
|
@@ -107,7 +106,7 @@ function updateEntityHandlerNgsiLD(deviceData, updatedDevice, callback) {
|
|
|
107
106
|
* @param {Object} deviceData Object containing all the deviceData needed to send the registration.
|
|
108
107
|
* @param {Object} newDevice Device object that will be stored in the database.
|
|
109
108
|
*/
|
|
110
|
-
function
|
|
109
|
+
function createInitialEntityNgsiLD(deviceData, newDevice, callback) {
|
|
111
110
|
callback(null, newDevice);
|
|
112
111
|
}
|
|
113
112
|
|
|
@@ -153,7 +152,7 @@ function updateEntityNgsiLD(deviceData, updatedDevice, callback) {
|
|
|
153
152
|
) {
|
|
154
153
|
options.json[constants.TIMESTAMP_ATTRIBUTE] = {
|
|
155
154
|
type: constants.TIMESTAMP_TYPE_NGSI2,
|
|
156
|
-
value:
|
|
155
|
+
value: new Date().toISOString()
|
|
157
156
|
};
|
|
158
157
|
}
|
|
159
158
|
|
|
@@ -285,7 +284,7 @@ function updateRegisterDeviceNgsiLD(deviceObj, previousDevice, entityInfoUpdated
|
|
|
285
284
|
deviceObj.subservice
|
|
286
285
|
),
|
|
287
286
|
apply(extractDeviceDifference, deviceObj),
|
|
288
|
-
|
|
287
|
+
createInitialEntityNgsiLD,
|
|
289
288
|
apply(combineWithNewDevice, deviceObj),
|
|
290
289
|
apply(registrationUtils.sendRegistrations, false),
|
|
291
290
|
apply(registrationUtils.processContextRegistration, deviceObj),
|
|
@@ -315,4 +314,5 @@ function updateRegisterDeviceNgsiLD(deviceObj, previousDevice, entityInfoUpdated
|
|
|
315
314
|
}
|
|
316
315
|
}
|
|
317
316
|
|
|
317
|
+
exports.createInitialEntity = createInitialEntityNgsiLD;
|
|
318
318
|
exports.updateRegisterDevice = updateRegisterDeviceNgsiLD;
|
|
@@ -27,6 +27,21 @@ const config = require('../../commonConfig');
|
|
|
27
27
|
const deviceHandlerLD = require('./devices-NGSI-LD');
|
|
28
28
|
const deviceHandlerV2 = require('./devices-NGSI-v2');
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Creates the initial entity representing the device in the Context Broker using both NGSI-LD and NGSI-v2
|
|
32
|
+
* This is important mainly to allow the rest of the updateContext operations to be performed.
|
|
33
|
+
*
|
|
34
|
+
* @param {Object} deviceData Object containing all the deviceData needed to send the registration.
|
|
35
|
+
* @param {Object} newDevice Device object that will be stored in the database.
|
|
36
|
+
*/
|
|
37
|
+
function createInitialEntityNgsiMixed(deviceData, newDevice, callback) {
|
|
38
|
+
if (config.checkNgsiLD(deviceData)) {
|
|
39
|
+
deviceHandlerLD.createInitialEntity(deviceData, newDevice, callback);
|
|
40
|
+
} else {
|
|
41
|
+
deviceHandlerV2.createInitialEntity(deviceData, newDevice, callback);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
30
45
|
/**
|
|
31
46
|
* Updates the register of an existing device identified by the Id and Type in the Context Broker, and the internal
|
|
32
47
|
* registry. It uses both NGSI-LD and NGSI-v2
|
|
@@ -46,4 +61,5 @@ function updateRegisterDeviceNgsiMixed(deviceObj, previousDevice, entityInfoUpda
|
|
|
46
61
|
}
|
|
47
62
|
}
|
|
48
63
|
|
|
64
|
+
exports.createInitialEntity = createInitialEntityNgsiMixed;
|
|
49
65
|
exports.updateRegisterDevice = updateRegisterDeviceNgsiMixed;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright 2020 Telefonica
|
|
2
|
+
* Copyright 2020 Telefonica Investigación y Desarrollo, S.A.U
|
|
3
3
|
*
|
|
4
4
|
* This file is part of fiware-iotagent-lib
|
|
5
5
|
*
|
|
@@ -41,7 +41,6 @@ const registrationUtils = require('./registrationUtils');
|
|
|
41
41
|
const _ = require('underscore');
|
|
42
42
|
const utils = require('../northBound/restUtils');
|
|
43
43
|
const NGSIv2 = require('../ngsi/entities-NGSI-v2');
|
|
44
|
-
const moment = require('moment');
|
|
45
44
|
const context = {
|
|
46
45
|
op: 'IoTAgentNGSI.Devices-v2'
|
|
47
46
|
};
|
|
@@ -165,12 +164,102 @@ function formatCommandsNgsi2(originalVector) {
|
|
|
165
164
|
return attributeList;
|
|
166
165
|
}
|
|
167
166
|
|
|
167
|
+
function formatCommandsBySubsNgsi2(originalVector) {
|
|
168
|
+
const attributeList = {};
|
|
169
|
+
|
|
170
|
+
if (originalVector && originalVector.length) {
|
|
171
|
+
for (let i = 0; i < originalVector.length; i++) {
|
|
172
|
+
attributeList[originalVector[i].name] = {
|
|
173
|
+
type: 'command',
|
|
174
|
+
value: null
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return attributeList;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function createInitialEntityHandlerNgsi2(deviceData, newDevice, callback) {
|
|
183
|
+
return function handleInitialEntityResponse(error, response, body) {
|
|
184
|
+
if (error) {
|
|
185
|
+
logger.error(
|
|
186
|
+
context,
|
|
187
|
+
'ORION-001: Connection error creating inital entity in the Context Broker: %s',
|
|
188
|
+
error
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
alarms.raise(constants.ORION_ALARM, error);
|
|
192
|
+
|
|
193
|
+
callback(error);
|
|
194
|
+
} else if (response && response.statusCode === 204) {
|
|
195
|
+
alarms.release(constants.ORION_ALARM);
|
|
196
|
+
logger.debug(context, 'Initial entity created successfully.');
|
|
197
|
+
callback(null, newDevice);
|
|
198
|
+
} else {
|
|
199
|
+
logger.error(
|
|
200
|
+
context,
|
|
201
|
+
'Protocol error connecting to the Context Broker [%d]: %s',
|
|
202
|
+
response.statusCode,
|
|
203
|
+
body
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
const errorObj = new errors.EntityGenericError(newDevice.id, newDevice.type, body, response.statusCode);
|
|
207
|
+
|
|
208
|
+
callback(errorObj);
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
168
213
|
/*
|
|
169
214
|
* This methods makes a bypass in updateRegisterDeviceNgsi2 to allow not change
|
|
170
215
|
* extractDeviceDifference and combineWithNewDevice methods
|
|
171
216
|
*/
|
|
172
|
-
function
|
|
173
|
-
|
|
217
|
+
function createInitialEntityNgsi2(newDevice, deviceObj, callback) {
|
|
218
|
+
logger.debug(context, 'createInitialEntityNgsiv2 called with newDevice: %j', newDevice);
|
|
219
|
+
|
|
220
|
+
const cmdModeConfig = config.getConfig().cmdMode;
|
|
221
|
+
|
|
222
|
+
const isLegacy =
|
|
223
|
+
(!newDevice.cmdMode && (!cmdModeConfig || cmdModeConfig === 'legacy')) || newDevice.cmdMode === 'legacy';
|
|
224
|
+
if (isLegacy) {
|
|
225
|
+
logger.debug(context, 'Old cmdMode with newDevice: %j', deviceObj);
|
|
226
|
+
return callback(null, deviceObj);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (!Array.isArray(newDevice.commands) || newDevice.commands.length === 0) {
|
|
230
|
+
logger.debug(context, 'No initial entity due to no commands by subs in newDevice: %j', newDevice);
|
|
231
|
+
return callback(null, deviceObj);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const entityPayload = {
|
|
235
|
+
id: String(newDevice.name),
|
|
236
|
+
type: newDevice.type
|
|
237
|
+
};
|
|
238
|
+
jsonConcat(entityPayload, formatCommandsBySubsNgsi2(newDevice.commands));
|
|
239
|
+
|
|
240
|
+
let url = config.getConfig().contextBroker.url + '/v2/entities?options=upsert';
|
|
241
|
+
if (newDevice.cbHost) {
|
|
242
|
+
url = newDevice.cbHost.includes('://')
|
|
243
|
+
? newDevice.cbHost + '/v2/entities?options=upsert'
|
|
244
|
+
: 'http://' + newDevice.cbHost + '/v2/entities?options=upsert';
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const headers = {
|
|
248
|
+
'fiware-correlator': (domain.active && domain.active.corr) || uuid.v4()
|
|
249
|
+
};
|
|
250
|
+
if (newDevice.service) headers['fiware-service'] = newDevice.service;
|
|
251
|
+
if (newDevice.subservice) headers['fiware-servicepath'] = newDevice.subservice;
|
|
252
|
+
|
|
253
|
+
const options = { url, method: 'POST', json: entityPayload, headers };
|
|
254
|
+
|
|
255
|
+
logger.debug(context, 'Creating initial entity due to commands by subs with newDevice: %j', newDevice);
|
|
256
|
+
logger.debug(context, 'Creating initial entity in the Context Broker:\n %s', JSON.stringify(options, null, 4));
|
|
257
|
+
|
|
258
|
+
return utils.executeWithSecurity(
|
|
259
|
+
options,
|
|
260
|
+
newDevice,
|
|
261
|
+
createInitialEntityHandlerNgsi2(newDevice, deviceObj, callback)
|
|
262
|
+
);
|
|
174
263
|
}
|
|
175
264
|
|
|
176
265
|
/**
|
|
@@ -180,6 +269,7 @@ function createInitialEntityNgsi2Fake(deviceData, newDevice, callback) {
|
|
|
180
269
|
* @param {Object} updatedDevice Device object that will be stored in the database.
|
|
181
270
|
*/
|
|
182
271
|
function updateEntityNgsi2(deviceData, updatedDevice, callback) {
|
|
272
|
+
logger.debug(context, 'updateEntityNgsi2 called with deviceData: %j updatedDevice: %j', deviceData, updatedDevice);
|
|
183
273
|
const options = {
|
|
184
274
|
url: config.getConfig().contextBroker.url + '/v2/entities/' + String(deviceData.name) + '/attrs',
|
|
185
275
|
method: 'POST',
|
|
@@ -203,7 +293,14 @@ function updateEntityNgsi2(deviceData, updatedDevice, callback) {
|
|
|
203
293
|
|
|
204
294
|
jsonConcat(options.json, formatAttributesNgsi2(deviceData.active, false));
|
|
205
295
|
jsonConcat(options.json, formatAttributesNgsi2(deviceData.staticAttributes, true));
|
|
206
|
-
|
|
296
|
+
if (
|
|
297
|
+
(!updatedDevice.cmdMode && (!config.getConfig().cmdMode || config.getConfig().cmdMode === 'legacy')) ||
|
|
298
|
+
(updatedDevice && updatedDevice.cmdMode === 'legacy')
|
|
299
|
+
) {
|
|
300
|
+
jsonConcat(options.json, formatCommandsNgsi2(deviceData.commands));
|
|
301
|
+
} else {
|
|
302
|
+
jsonConcat(options.json, formatCommandsBySubsNgsi2(deviceData.commands));
|
|
303
|
+
}
|
|
207
304
|
|
|
208
305
|
for (const att in options.json) {
|
|
209
306
|
try {
|
|
@@ -222,7 +319,7 @@ function updateEntityNgsi2(deviceData, updatedDevice, callback) {
|
|
|
222
319
|
) {
|
|
223
320
|
options.json[constants.TIMESTAMP_ATTRIBUTE] = {
|
|
224
321
|
type: constants.TIMESTAMP_TYPE_NGSI2,
|
|
225
|
-
value:
|
|
322
|
+
value: new Date().toISOString()
|
|
226
323
|
};
|
|
227
324
|
}
|
|
228
325
|
|
|
@@ -253,7 +350,13 @@ function updateRegisterDeviceNgsi2(deviceObj, previousDevice, entityInfoUpdated,
|
|
|
253
350
|
return;
|
|
254
351
|
}
|
|
255
352
|
|
|
256
|
-
logger.debug(
|
|
353
|
+
logger.debug(
|
|
354
|
+
context,
|
|
355
|
+
'Update provisioned v2 device %j with Device %j entityInfoUpdated %j',
|
|
356
|
+
previousDevice,
|
|
357
|
+
deviceObj,
|
|
358
|
+
entityInfoUpdated
|
|
359
|
+
);
|
|
257
360
|
|
|
258
361
|
function combineWithNewDevice(newDevice, oldDevice, callback) {
|
|
259
362
|
logger.debug(context, 'combineWithNewDevice %j %j', newDevice, oldDevice);
|
|
@@ -291,6 +394,9 @@ function updateRegisterDeviceNgsi2(deviceObj, previousDevice, entityInfoUpdated,
|
|
|
291
394
|
if ('storeLastMeasure' in newDevice && newDevice.storeLastMeasure !== undefined) {
|
|
292
395
|
oldDevice.storeLastMeasure = newDevice.storeLastMeasure;
|
|
293
396
|
}
|
|
397
|
+
if ('cmdMode' in newDevice && newDevice.cmdMode !== undefined) {
|
|
398
|
+
oldDevice.cmdMode = newDevice.cmdMode;
|
|
399
|
+
}
|
|
294
400
|
callback(null, oldDevice);
|
|
295
401
|
} else {
|
|
296
402
|
callback(new errors.DeviceNotFound(newDevice.id, newDevice));
|
|
@@ -338,7 +444,7 @@ function updateRegisterDeviceNgsi2(deviceObj, previousDevice, entityInfoUpdated,
|
|
|
338
444
|
if (entityInfoUpdated) {
|
|
339
445
|
jsonConcat(deviceData.active, oldDevice.active);
|
|
340
446
|
jsonConcat(deviceData.lazy, oldDevice.lazy);
|
|
341
|
-
|
|
447
|
+
deviceData.commands = deviceData.commands.concat(oldDevice.commands);
|
|
342
448
|
jsonConcat(deviceData.staticAttributes, oldDevice.staticAttributes);
|
|
343
449
|
if (oldDevice.name !== newDevice.name) {
|
|
344
450
|
deviceData.name = newDevice.name;
|
|
@@ -347,7 +453,13 @@ function updateRegisterDeviceNgsi2(deviceObj, previousDevice, entityInfoUpdated,
|
|
|
347
453
|
deviceData.type = newDevice.type;
|
|
348
454
|
}
|
|
349
455
|
}
|
|
350
|
-
|
|
456
|
+
logger.debug(
|
|
457
|
+
context,
|
|
458
|
+
'extractDeviceDifference newDevice %j oldDevice %j difference %j',
|
|
459
|
+
newDevice,
|
|
460
|
+
oldDevice,
|
|
461
|
+
deviceData
|
|
462
|
+
);
|
|
351
463
|
callback(null, deviceData, oldDevice);
|
|
352
464
|
}
|
|
353
465
|
|
|
@@ -362,7 +474,7 @@ function updateRegisterDeviceNgsi2(deviceObj, previousDevice, entityInfoUpdated,
|
|
|
362
474
|
deviceObj.subservice
|
|
363
475
|
),
|
|
364
476
|
apply(extractDeviceDifference, deviceObj),
|
|
365
|
-
|
|
477
|
+
createInitialEntityNgsi2,
|
|
366
478
|
apply(combineWithNewDevice, deviceObj),
|
|
367
479
|
apply(registrationUtils.sendRegistrations, false),
|
|
368
480
|
apply(registrationUtils.processContextRegistration, deviceObj),
|
|
@@ -392,6 +504,7 @@ function updateRegisterDeviceNgsi2(deviceObj, previousDevice, entityInfoUpdated,
|
|
|
392
504
|
}
|
|
393
505
|
}
|
|
394
506
|
|
|
507
|
+
exports.createInitialEntity = createInitialEntityNgsi2;
|
|
395
508
|
exports.updateRegisterDevice = updateRegisterDeviceNgsi2;
|
|
396
509
|
exports.formatCommands = formatCommandsNgsi2;
|
|
397
510
|
exports.formatAttributes = formatAttributesNgsi2;
|
|
@@ -36,6 +36,7 @@ const context = {
|
|
|
36
36
|
};
|
|
37
37
|
const async = require('async');
|
|
38
38
|
const utils = require('../northBound/restUtils');
|
|
39
|
+
const subscriptionService = require('../ngsi/subscriptionService');
|
|
39
40
|
|
|
40
41
|
const NGSI_LD_URN = 'urn:ngsi-ld:';
|
|
41
42
|
|
|
@@ -203,6 +204,23 @@ function sendUnregistrationsNgsiLD(deviceData, callback) {
|
|
|
203
204
|
return callback(null, deviceData);
|
|
204
205
|
}
|
|
205
206
|
|
|
207
|
+
function formatAttributes(originalVector) {
|
|
208
|
+
const attributeList = [];
|
|
209
|
+
if (originalVector && originalVector.length) {
|
|
210
|
+
for (let i = 0; i < originalVector.length; i++) {
|
|
211
|
+
attributeList.push(originalVector[i].name);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return attributeList;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function mergeWithSameName(old, current) {
|
|
218
|
+
if (old.indexOf(current) < 0) {
|
|
219
|
+
old.push(current);
|
|
220
|
+
}
|
|
221
|
+
return old;
|
|
222
|
+
}
|
|
223
|
+
|
|
206
224
|
/**
|
|
207
225
|
* Sends a Context Provider registration or unregistration request to the Context Broker using NGSIv2.
|
|
208
226
|
*
|
|
@@ -210,26 +228,6 @@ function sendUnregistrationsNgsiLD(deviceData, callback) {
|
|
|
210
228
|
* @param {Object} deviceData Object containing all the deviceData needed to send the registration.
|
|
211
229
|
*/
|
|
212
230
|
function sendRegistrationsNgsi2(unregister, deviceData, callback) {
|
|
213
|
-
function formatAttributes(originalVector) {
|
|
214
|
-
const attributeList = [];
|
|
215
|
-
|
|
216
|
-
if (originalVector && originalVector.length) {
|
|
217
|
-
for (let i = 0; i < originalVector.length; i++) {
|
|
218
|
-
attributeList.push(originalVector[i].name);
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
return attributeList;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
function mergeWithSameName(old, current) {
|
|
226
|
-
if (old.indexOf(current) < 0) {
|
|
227
|
-
old.push(current);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
return old;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
231
|
// FIXME: When https://github.com/telefonicaid/fiware-orion/issues/3007 is merged into master branch,
|
|
234
232
|
// this function should use the new API. This is just a temporary solution which implies deleting the
|
|
235
233
|
// registration and creating a new one.
|
|
@@ -299,6 +297,61 @@ function sendRegistrationsNgsi2(unregister, deviceData, callback) {
|
|
|
299
297
|
utils.executeWithSecurity(options, deviceData, createRegistrationHandlerNgsi2(unregister, deviceData, callback));
|
|
300
298
|
}
|
|
301
299
|
|
|
300
|
+
function sendUnsubscriptionsNgsi2(deviceData, callback) {
|
|
301
|
+
if (deviceData.subscriptionId) {
|
|
302
|
+
logger.debug(
|
|
303
|
+
context,
|
|
304
|
+
'Sending v2 device unsubscriptions to Context Broker at [%s]',
|
|
305
|
+
config.getConfig().contextBroker.url
|
|
306
|
+
);
|
|
307
|
+
logger.debug(context, 'Using the following subscriptionId %j', deviceData.subscriptionId);
|
|
308
|
+
subscriptionService.unsubscribe(deviceData, deviceData.subscriptionId, callback);
|
|
309
|
+
} else {
|
|
310
|
+
logger.debug(context, 'No subscription found for unregister');
|
|
311
|
+
return callback(null, deviceData);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function sendSubscriptionsNgsi2(unregister, deviceData, callback) {
|
|
316
|
+
function updateSubscriptionNgsi2(deviceData, callback) {
|
|
317
|
+
const functions = [];
|
|
318
|
+
|
|
319
|
+
function removeSubscriptionId(deviceData, unregistrationResult, callback) {
|
|
320
|
+
delete deviceData.subscriptionId;
|
|
321
|
+
return callback(null, deviceData);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
functions.push(async.apply(sendSubscriptionsNgsi2, true, deviceData));
|
|
325
|
+
functions.push(async.apply(removeSubscriptionId, deviceData));
|
|
326
|
+
functions.push(async.apply(sendSubscriptionsNgsi2, false));
|
|
327
|
+
async.waterfall(functions, callback);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
if (unregister) {
|
|
331
|
+
return sendUnsubscriptionsNgsi2(deviceData, callback);
|
|
332
|
+
}
|
|
333
|
+
if (deviceData.subscriptionId) {
|
|
334
|
+
return updateSubscriptionNgsi2(deviceData, callback);
|
|
335
|
+
}
|
|
336
|
+
const attrs = [].concat(formatAttributes(deviceData.commands)).reduce(mergeWithSameName, []);
|
|
337
|
+
|
|
338
|
+
if (attrs.length === 0) {
|
|
339
|
+
logger.debug(context, 'Subscription is not needed. Device without commands');
|
|
340
|
+
return callback(null, deviceData);
|
|
341
|
+
}
|
|
342
|
+
const trigger = attrs; // one subscription for all commands
|
|
343
|
+
const content = attrs;
|
|
344
|
+
const attrsFormat = 'simplifiedNormalized';
|
|
345
|
+
|
|
346
|
+
logger.debug(
|
|
347
|
+
context,
|
|
348
|
+
'Sending v2 device subscriptions to Context Broker at [%s]',
|
|
349
|
+
config.getConfig().contextBroker.url
|
|
350
|
+
);
|
|
351
|
+
logger.debug(context, 'Using the following trigger %j and content %j', trigger, content);
|
|
352
|
+
subscriptionService.subscribe(deviceData, trigger, content, attrsFormat, callback);
|
|
353
|
+
}
|
|
354
|
+
|
|
302
355
|
/**
|
|
303
356
|
* Sends a Context Provider registration or unregistration request to the Context Broker using NGSI-LD.
|
|
304
357
|
*
|
|
@@ -323,14 +376,14 @@ function sendRegistrationsNgsiLD(unregister, deviceData, callback) {
|
|
|
323
376
|
properties.push(element.name);
|
|
324
377
|
});
|
|
325
378
|
|
|
326
|
-
if (lazy.length > 0){
|
|
327
|
-
operations.push('retrieveOps');
|
|
379
|
+
if (lazy.length > 0) {
|
|
380
|
+
operations.push('retrieveOps');
|
|
328
381
|
}
|
|
329
|
-
if (commands.length > 0){
|
|
330
|
-
|
|
382
|
+
if (commands.length > 0) {
|
|
383
|
+
operations.push('updateOps');
|
|
331
384
|
}
|
|
332
|
-
if (supportMerge){
|
|
333
|
-
operations.push('mergeEntity');
|
|
385
|
+
if (supportMerge) {
|
|
386
|
+
operations.push('mergeEntity');
|
|
334
387
|
}
|
|
335
388
|
|
|
336
389
|
if (properties.length === 0) {
|
|
@@ -368,8 +421,8 @@ function sendRegistrationsNgsiLD(unregister, deviceData, callback) {
|
|
|
368
421
|
endpoint: config.getConfig().providerUrl,
|
|
369
422
|
contextSourceInfo: [
|
|
370
423
|
{
|
|
371
|
-
|
|
372
|
-
|
|
424
|
+
key: 'jsonldContext',
|
|
425
|
+
value: config.getConfig().contextBroker.jsonLdContext
|
|
373
426
|
}
|
|
374
427
|
],
|
|
375
428
|
'@context': config.getConfig().contextBroker.jsonLdContext
|
|
@@ -405,7 +458,14 @@ function sendRegistrations(unregister, deviceData, callback) {
|
|
|
405
458
|
sendRegistrationsNgsiLD(unregister, deviceData, callback);
|
|
406
459
|
break;
|
|
407
460
|
default:
|
|
408
|
-
|
|
461
|
+
if (
|
|
462
|
+
(!deviceData.cmdMode && (!config.getConfig().cmdMode || config.getConfig().cmdMode === 'legacy')) ||
|
|
463
|
+
(deviceData && deviceData.cmdMode === 'legacy')
|
|
464
|
+
) {
|
|
465
|
+
sendRegistrationsNgsi2(unregister, deviceData, callback);
|
|
466
|
+
} else {
|
|
467
|
+
sendSubscriptionsNgsi2(unregister, deviceData, callback);
|
|
468
|
+
}
|
|
409
469
|
break;
|
|
410
470
|
}
|
|
411
471
|
}
|
|
@@ -421,7 +481,14 @@ function processContextRegistration(deviceData, body, callback) {
|
|
|
421
481
|
const newDevice = _.clone(deviceData);
|
|
422
482
|
|
|
423
483
|
if (body) {
|
|
424
|
-
|
|
484
|
+
if (
|
|
485
|
+
(!deviceData.cmdMode && (!config.getConfig().cmdMode || config.getConfig().cmdMode === 'legacy')) ||
|
|
486
|
+
(deviceData && deviceData.cmdMode === 'legacy')
|
|
487
|
+
) {
|
|
488
|
+
newDevice.registrationId = body.registrationId;
|
|
489
|
+
} else {
|
|
490
|
+
newDevice.subscriptionId = body.subscriptionId;
|
|
491
|
+
}
|
|
425
492
|
}
|
|
426
493
|
|
|
427
494
|
callback(null, newDevice);
|