iotagent-node-lib 3.4.4 → 4.0.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/README.md +4 -0
- package/doc/admin.md +1 -13
- package/doc/api.md +116 -18
- package/doc/devel/architecture.md +0 -12
- package/doc/index.md +1 -1
- package/doc/roadmap.md +22 -10
- package/lib/commonConfig.js +0 -11
- package/lib/errors.js +2 -2
- package/lib/model/Device.js +2 -1
- package/lib/model/Group.js +2 -1
- package/lib/model/dbConn.js +22 -11
- package/lib/plugins/expressionPlugin.js +0 -5
- package/lib/plugins/jexlParser.js +15 -31
- package/lib/services/common/genericMiddleware.js +14 -2
- package/lib/services/common/iotManagerService.js +2 -1
- package/lib/services/devices/deviceRegistryMongoDB.js +3 -1
- package/lib/services/devices/deviceService.js +16 -21
- package/lib/services/devices/devices-NGSI-LD.js +5 -98
- package/lib/services/devices/devices-NGSI-mixed.js +0 -14
- package/lib/services/devices/devices-NGSI-v2.js +3 -0
- package/lib/services/groups/groupRegistryMemory.js +0 -25
- package/lib/services/groups/groupRegistryMongoDB.js +20 -19
- package/lib/services/groups/groupService.js +3 -14
- package/lib/services/ngsi/entities-NGSI-LD.js +82 -7
- package/lib/services/ngsi/entities-NGSI-v2.js +297 -696
- package/lib/services/ngsi/ngsiUtils.js +0 -30
- package/lib/services/northBound/deviceProvisioningServer.js +6 -3
- package/lib/templates/createDevice.json +4 -0
- package/lib/templates/createDeviceLax.json +4 -0
- package/lib/templates/deviceGroup.json +4 -0
- package/lib/templates/updateDevice.json +4 -0
- package/lib/templates/updateDeviceLax.json +4 -0
- package/package.json +6 -2
- package/test/functional/README.md +378 -0
- package/test/functional/config-test.js +70 -0
- package/test/functional/functional-tests-runner.js +126 -0
- package/test/functional/functional-tests.js +241 -0
- package/test/functional/testCases.js +2944 -0
- package/test/functional/testUtils.js +251 -0
- package/test/tools/utils.js +25 -0
- package/test/unit/mongodb/mongodb-connectionoptions-test.js +35 -22
- package/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDeviceWithGroupAndStatic2.json +3 -34
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin6.json +8 -1
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin7.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin8.json +1 -6
- package/test/unit/ngsi-ld/general/contextBrokerOAuthSecurityAccess-test.js +67 -87
- package/test/unit/ngsi-ld/lazyAndCommands/command-test.js +7 -13
- package/test/unit/ngsi-ld/lazyAndCommands/merge-patch-test.js +43 -43
- package/test/unit/ngsi-ld/lazyAndCommands/polling-commands-test.js +19 -29
- package/test/unit/ngsi-ld/ngsiService/languageProperties-test.js +0 -1
- package/test/unit/ngsi-ld/ngsiService/subscriptions-test.js +35 -46
- package/test/unit/ngsi-ld/plugins/alias-plugin_test.js +8 -9
- package/test/unit/ngsi-ld/provisioning/device-provisioning-api_test.js +96 -221
- package/test/unit/ngsi-ld/provisioning/device-registration_test.js +18 -27
- package/test/unit/ngsi-ld/provisioning/device-update-registration_test.js +8 -16
- package/test/unit/ngsi-ld/provisioning/updateProvisionedDevices-test.js +0 -13
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin8.json +4 -4
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin29b.json +8 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin30.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin32.json +0 -6
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin34.json +8 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin34b.json +14 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin35.json +1 -11
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin36b.json +13 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin37.json +8 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin41.json +1 -11
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin10b.json +37 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin11.json +0 -4
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin15.json +0 -4
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin16.json +0 -4
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin25.json +4 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin4.json +0 -3
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin5.json +10 -12
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin6.json +0 -4
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin7.json +1 -5
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin8.json +8 -12
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin2.json +0 -4
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin3.json +0 -8
- package/test/unit/ngsiv2/examples/contextRequests/updateContextStaticAttributesMetadata.json +7 -1
- package/test/unit/ngsiv2/expressions/jexlBasedTransformations-test.js +898 -28
- package/test/unit/ngsiv2/ngsiService/active-devices-test.js +0 -4
- package/test/unit/ngsiv2/ngsiService/staticAttributes-test.js +267 -0
- package/test/unit/ngsiv2/plugins/alias-plugin_test.js +19 -21
- package/test/unit/ngsiv2/plugins/multientity-plugin_test.js +21 -24
- package/test/unit/ngsiv2/provisioning/device-group-utils-test.js +1 -21
- package/test/unit/ngsiv2/provisioning/device-provisioning-api_test.js +4 -6
- package/CHANGES_NEXT_RELEASE +0 -0
- package/test/unit/ngsi-ld/ngsiService/autocast-test.js +0 -438
- package/test/unit/ngsi-ld/ngsiService/geoproperties-test.js +0 -381
- package/test/unit/ngsi-ld/provisioning/singleConfigurationMode-test.js +0 -311
- package/test/unit/ngsiv2/ngsiService/autocast-test.js +0 -325
- package/test/unit/ngsiv2/ngsiService/geoproperties-test.js +0 -427
- package/test/unit/ngsiv2/plugins/compress-timestamp-plugin_test.js +0 -217
- package/test/unit/ngsiv2/plugins/timestamp-processing-plugin_test.js +0 -119
- package/test/unit/ngsiv2/provisioning/singleConfigurationMode-test.js +0 -309
|
@@ -24,8 +24,9 @@
|
|
|
24
24
|
const logger = require('logops');
|
|
25
25
|
const revalidator = require('revalidator');
|
|
26
26
|
const errors = require('../../errors');
|
|
27
|
+
const fillService = require('./domain').fillService;
|
|
27
28
|
let iotaInformation;
|
|
28
|
-
|
|
29
|
+
let context = {
|
|
29
30
|
op: 'IoTAgentNGSI.GenericMiddlewares'
|
|
30
31
|
};
|
|
31
32
|
|
|
@@ -39,7 +40,10 @@ const context = {
|
|
|
39
40
|
/* eslint-disable-next-line no-unused-vars */
|
|
40
41
|
function handleError(error, req, res, next) {
|
|
41
42
|
let code = 500;
|
|
42
|
-
|
|
43
|
+
context = fillService(context, {
|
|
44
|
+
service: req.headers['fiware-service'],
|
|
45
|
+
subservice: req.headers['fiware-servicepath']
|
|
46
|
+
});
|
|
43
47
|
logger.debug(context, 'Error [%s] handling request: %s', error.name, error.message);
|
|
44
48
|
|
|
45
49
|
if (error.code && String(error.code).match(/^[2345]\d\d$/)) {
|
|
@@ -56,6 +60,10 @@ function handleError(error, req, res, next) {
|
|
|
56
60
|
* Express middleware for tracing the complete request arriving to the IoTA in debug mode.
|
|
57
61
|
*/
|
|
58
62
|
function traceRequest(req, res, next) {
|
|
63
|
+
context = fillService(context, {
|
|
64
|
+
service: req.headers['fiware-service'],
|
|
65
|
+
subservice: req.headers['fiware-servicepath']
|
|
66
|
+
});
|
|
59
67
|
logger.debug(context, 'Request for path [%s] query [%j] from [%s]', req.path, req.query, req.get('host'));
|
|
60
68
|
|
|
61
69
|
if (req.is('json') || req.is('application/ld+json')) {
|
|
@@ -129,6 +137,10 @@ function validateJson(template) {
|
|
|
129
137
|
if (errorList.valid) {
|
|
130
138
|
next();
|
|
131
139
|
} else {
|
|
140
|
+
context = fillService(context, {
|
|
141
|
+
service: req.headers['fiware-service'],
|
|
142
|
+
subservice: req.headers['fiware-servicepath']
|
|
143
|
+
});
|
|
132
144
|
logger.debug(context, 'Errors found validating request: %j', errorList);
|
|
133
145
|
next(new errors.BadRequest('Errors found validating request.'));
|
|
134
146
|
}
|
|
@@ -60,7 +60,8 @@ function register(callback) {
|
|
|
60
60
|
explicitAttrs: service.explicitAttrs,
|
|
61
61
|
defaultEntityNameConjunction: service.defaultEntityNameConjunction,
|
|
62
62
|
ngsiVersion: service.ngsiVersion,
|
|
63
|
-
entityNameExp: service.entityNameExp
|
|
63
|
+
entityNameExp: service.entityNameExp,
|
|
64
|
+
payloadType: service.payloadType
|
|
64
65
|
};
|
|
65
66
|
}
|
|
66
67
|
|
|
@@ -55,7 +55,8 @@ const attributeList = [
|
|
|
55
55
|
'polling',
|
|
56
56
|
'timestamp',
|
|
57
57
|
'explicitAttrs',
|
|
58
|
-
'ngsiVersion'
|
|
58
|
+
'ngsiVersion',
|
|
59
|
+
'payloadType'
|
|
59
60
|
];
|
|
60
61
|
|
|
61
62
|
/**
|
|
@@ -316,6 +317,7 @@ function update(device, callback) {
|
|
|
316
317
|
data.explicitAttrs = device.explicitAttrs;
|
|
317
318
|
data.ngsiVersion = device.ngsiVersion;
|
|
318
319
|
data.timestamp = device.timestamp;
|
|
320
|
+
data.payloadType = device.payloadType;
|
|
319
321
|
|
|
320
322
|
/* eslint-disable-next-line new-cap */
|
|
321
323
|
const deviceObj = new Device.model(data);
|
|
@@ -173,13 +173,18 @@ function mergeDeviceWithConfiguration(fields, defaults, deviceData, configuratio
|
|
|
173
173
|
if (configuration && configuration.entityNameExp !== undefined) {
|
|
174
174
|
deviceData.entityNameExp = configuration.entityNameExp;
|
|
175
175
|
}
|
|
176
|
+
if (configuration && configuration.timestamp !== undefined && deviceData.timestamp === undefined) {
|
|
177
|
+
deviceData.timestamp = configuration.timestamp;
|
|
178
|
+
}
|
|
179
|
+
if (configuration && configuration.payloadType !== undefined && deviceData.payloadType === undefined) {
|
|
180
|
+
deviceData.payloadType = configuration.payloadType;
|
|
181
|
+
}
|
|
176
182
|
logger.debug(context, 'deviceData after merge with conf: %j', deviceData);
|
|
177
183
|
callback(null, deviceData);
|
|
178
184
|
}
|
|
179
185
|
|
|
180
186
|
/**
|
|
181
|
-
* Find the configuration group belonging to a given device
|
|
182
|
-
* agent is in single configuration mode or node.
|
|
187
|
+
* Find the configuration group belonging to a given device
|
|
183
188
|
*
|
|
184
189
|
* @param {Object} deviceObj Device data.
|
|
185
190
|
*/
|
|
@@ -206,19 +211,15 @@ function findConfigurationGroup(deviceObj, callback) {
|
|
|
206
211
|
callback(null, effectiveGroup);
|
|
207
212
|
}
|
|
208
213
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
.
|
|
214
|
-
.
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
deviceObj.apikey,
|
|
219
|
-
handlerGroupFindByType
|
|
220
|
-
);
|
|
221
|
-
}
|
|
214
|
+
config
|
|
215
|
+
.getGroupRegistry()
|
|
216
|
+
.findTypeSilently(
|
|
217
|
+
deviceObj.service,
|
|
218
|
+
deviceObj.subservice,
|
|
219
|
+
deviceObj.type,
|
|
220
|
+
deviceObj.apikey,
|
|
221
|
+
handlerGroupFindByType
|
|
222
|
+
);
|
|
222
223
|
}
|
|
223
224
|
|
|
224
225
|
/**
|
|
@@ -353,12 +354,6 @@ function registerDevice(deviceObj, callback) {
|
|
|
353
354
|
deviceObj.staticAttributes = deviceObj.staticAttributes ? deviceObj.staticAttributes : [];
|
|
354
355
|
deviceObj.commands = deviceObj.commands ? deviceObj.commands : [];
|
|
355
356
|
deviceObj.lazy = deviceObj.lazy ? deviceObj.lazy : [];
|
|
356
|
-
if ('timestamp' in deviceData && deviceData.timestamp !== undefined) {
|
|
357
|
-
deviceObj.timestamp = deviceData.timestamp;
|
|
358
|
-
}
|
|
359
|
-
if ('explicitAttrs' in deviceData && deviceData.explicitAttrs !== undefined) {
|
|
360
|
-
deviceObj.explicitAttrs = deviceData.explicitAttrs;
|
|
361
|
-
}
|
|
362
357
|
if ('apikey' in deviceData && deviceData.apikey !== undefined) {
|
|
363
358
|
deviceObj.apikey = deviceData.apikey;
|
|
364
359
|
}
|
|
@@ -56,53 +56,6 @@ function jsonConcat(json1, json2) {
|
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
/**
|
|
60
|
-
* Creates the response handler for the initial entity creation request using NGSI-LD.
|
|
61
|
-
* This handler basically deals with the errors that could have been rised during
|
|
62
|
-
* the communication with the Context Broker.
|
|
63
|
-
*
|
|
64
|
-
* @param {Object} deviceData Object containing all the deviceData needed to send the registration.
|
|
65
|
-
* @param {Object} newDevice Device object that will be stored in the database.
|
|
66
|
-
* @return {function} Handler to pass to the request() function.
|
|
67
|
-
*/
|
|
68
|
-
function createInitialEntityHandlerNgsiLD(deviceData, newDevice, callback) {
|
|
69
|
-
return function handleInitialEntityResponse(error, response, body) {
|
|
70
|
-
if (error) {
|
|
71
|
-
logger.error(
|
|
72
|
-
context,
|
|
73
|
-
'ORION-001: Connection error creating inital entity in the Context Broker: %s',
|
|
74
|
-
error
|
|
75
|
-
);
|
|
76
|
-
|
|
77
|
-
alarms.raise(constants.ORION_ALARM, error);
|
|
78
|
-
|
|
79
|
-
callback(error);
|
|
80
|
-
}
|
|
81
|
-
// Handling different response codes for batch entity upsert in NGSI-LD specification:
|
|
82
|
-
// - In v1.2.1, response code is 200
|
|
83
|
-
// - In v1.3.1, response code is 201 if some created entities, 204 if just updated existing
|
|
84
|
-
else if (
|
|
85
|
-
response &&
|
|
86
|
-
(response.statusCode === 200 || response.statusCode === 201 || response.statusCode === 204)
|
|
87
|
-
) {
|
|
88
|
-
alarms.release(constants.ORION_ALARM);
|
|
89
|
-
logger.debug(context, 'Initial entity created successfully.');
|
|
90
|
-
callback(null, newDevice);
|
|
91
|
-
} else {
|
|
92
|
-
logger.error(
|
|
93
|
-
context,
|
|
94
|
-
'Protocol error connecting to the Context Broker [%d]: %s',
|
|
95
|
-
response.statusCode,
|
|
96
|
-
body
|
|
97
|
-
);
|
|
98
|
-
|
|
99
|
-
const errorObj = new errors.EntityGenericError(deviceData.id, deviceData.type, body);
|
|
100
|
-
|
|
101
|
-
callback(errorObj);
|
|
102
|
-
}
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
|
|
106
59
|
/**
|
|
107
60
|
* Creates the response handler for the update entity request using NGSI-LD.
|
|
108
61
|
* This handler basically deals with the errors
|
|
@@ -154,54 +107,8 @@ function updateEntityHandlerNgsiLD(deviceData, updatedDevice, callback) {
|
|
|
154
107
|
* @param {Object} deviceData Object containing all the deviceData needed to send the registration.
|
|
155
108
|
* @param {Object} newDevice Device object that will be stored in the database.
|
|
156
109
|
*/
|
|
157
|
-
function
|
|
158
|
-
|
|
159
|
-
id: String(deviceData.name),
|
|
160
|
-
type: deviceData.type
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
jsonConcat(json, NGSIv2.formatAttributes(deviceData.active, false));
|
|
164
|
-
jsonConcat(json, NGSIv2.formatAttributes(deviceData.staticAttributes, true));
|
|
165
|
-
jsonConcat(json, NGSIv2.formatCommands(deviceData.commands));
|
|
166
|
-
|
|
167
|
-
if (
|
|
168
|
-
('timestamp' in deviceData && deviceData.timestamp !== undefined
|
|
169
|
-
? deviceData.timestamp
|
|
170
|
-
: config.getConfig().timestamp) &&
|
|
171
|
-
!utils.isTimestampedNgsi2(json)
|
|
172
|
-
) {
|
|
173
|
-
logger.debug(context, 'config.timestamp %s %s', deviceData.timestamp, config.getConfig().timestamp);
|
|
174
|
-
|
|
175
|
-
json[constants.TIMESTAMP_ATTRIBUTE] = {
|
|
176
|
-
type: constants.TIMESTAMP_TYPE_NGSI2,
|
|
177
|
-
value: moment()
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
json = ngsiLD.formatAsNGSILD(json);
|
|
182
|
-
|
|
183
|
-
const options = {
|
|
184
|
-
url: config.getConfig().contextBroker.url + '/ngsi-ld/v1/entityOperations/upsert/',
|
|
185
|
-
method: 'POST',
|
|
186
|
-
json: [json],
|
|
187
|
-
headers: {
|
|
188
|
-
'fiware-service': deviceData.service,
|
|
189
|
-
'fiware-servicepath': deviceData.subservice,
|
|
190
|
-
'NGSILD-Tenant': deviceData.service,
|
|
191
|
-
'NGSILD-Path': deviceData.subservice,
|
|
192
|
-
'Content-Type': 'application/ld+json'
|
|
193
|
-
}
|
|
194
|
-
};
|
|
195
|
-
|
|
196
|
-
if (deviceData.cbHost && deviceData.cbHost.indexOf('://') !== -1) {
|
|
197
|
-
options.url = deviceData.cbHost + '/ngsi-ld/v1/entityOperations/upsert/';
|
|
198
|
-
} else if (deviceData.cbHost && deviceData.cbHost.indexOf('://') === -1) {
|
|
199
|
-
options.url = 'http://' + deviceData.cbHost + '/ngsi-ld/v1/entityOperations/upsert/';
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
logger.debug(context, 'deviceData: %j', deviceData);
|
|
203
|
-
logger.debug(context, 'Creating initial entity in the Context Broker:\n %s', JSON.stringify(options, null, 4));
|
|
204
|
-
utils.executeWithSecurity(options, newDevice, createInitialEntityHandlerNgsiLD(deviceData, newDevice, callback));
|
|
110
|
+
function createInitialEntityNgsiLDFake(deviceData, newDevice, callback) {
|
|
111
|
+
callback(null, newDevice);
|
|
205
112
|
}
|
|
206
113
|
|
|
207
114
|
/**
|
|
@@ -281,9 +188,10 @@ function updateRegisterDeviceNgsiLD(deviceObj, entityInfoUpdated, callback) {
|
|
|
281
188
|
return;
|
|
282
189
|
}
|
|
283
190
|
|
|
284
|
-
logger.debug(context, 'Update provisioned LD device in Device Service');
|
|
191
|
+
logger.debug(context, 'Update provisioned LD device in Device Service %j %j', deviceObj, entityInfoUpdated);
|
|
285
192
|
|
|
286
193
|
function combineWithNewDevice(newDevice, oldDevice, callback) {
|
|
194
|
+
logger.debug(context, 'combineWithNewDevice %j %j', newDevice, oldDevice);
|
|
287
195
|
if (oldDevice) {
|
|
288
196
|
oldDevice.internalId = newDevice.internalId;
|
|
289
197
|
oldDevice.lazy = newDevice.lazy;
|
|
@@ -377,7 +285,7 @@ function updateRegisterDeviceNgsiLD(deviceObj, entityInfoUpdated, callback) {
|
|
|
377
285
|
deviceObj.subservice
|
|
378
286
|
),
|
|
379
287
|
apply(extractDeviceDifference, deviceObj),
|
|
380
|
-
|
|
288
|
+
createInitialEntityNgsiLDFake,
|
|
381
289
|
apply(combineWithNewDevice, deviceObj),
|
|
382
290
|
apply(registrationUtils.sendRegistrations, false),
|
|
383
291
|
apply(registrationUtils.processContextRegistration, deviceObj),
|
|
@@ -407,5 +315,4 @@ function updateRegisterDeviceNgsiLD(deviceObj, entityInfoUpdated, callback) {
|
|
|
407
315
|
}
|
|
408
316
|
}
|
|
409
317
|
|
|
410
|
-
exports.createInitialEntity = createInitialEntityNgsiLD;
|
|
411
318
|
exports.updateRegisterDevice = updateRegisterDeviceNgsiLD;
|
|
@@ -27,19 +27,6 @@ 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
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
30
|
/**
|
|
44
31
|
* Updates the register of an existing device identified by the Id and Type in the Context Broker, and the internal
|
|
45
32
|
* registry. It uses both NGSI-LD and NGSI-v2
|
|
@@ -59,5 +46,4 @@ function updateRegisterDeviceNgsiMixed(deviceObj, entityInfoUpdated, callback) {
|
|
|
59
46
|
}
|
|
60
47
|
}
|
|
61
48
|
|
|
62
|
-
exports.createInitialEntity = createInitialEntityNgsiMixed;
|
|
63
49
|
exports.updateRegisterDevice = updateRegisterDeviceNgsiMixed;
|
|
@@ -270,6 +270,9 @@ function updateRegisterDeviceNgsi2(deviceObj, entityInfoUpdated, callback) {
|
|
|
270
270
|
if ('apikey' in newDevice && newDevice.apikey !== undefined) {
|
|
271
271
|
oldDevice.apikey = newDevice.apikey;
|
|
272
272
|
}
|
|
273
|
+
if ('payloadType' in newDevice && newDevice.payloadType !== undefined) {
|
|
274
|
+
oldDevice.payloadType = newDevice.payloadType;
|
|
275
|
+
}
|
|
273
276
|
oldDevice.endpoint = newDevice.endpoint || oldDevice.endpoint;
|
|
274
277
|
|
|
275
278
|
callback(null, oldDevice);
|
|
@@ -27,7 +27,6 @@ let registeredGroups = {};
|
|
|
27
27
|
const logger = require('logops');
|
|
28
28
|
const intoTrans = require('../common/domain').intoTrans;
|
|
29
29
|
const errors = require('../../errors');
|
|
30
|
-
const config = require('../../commonConfig');
|
|
31
30
|
const _ = require('underscore');
|
|
32
31
|
const context = {
|
|
33
32
|
op: 'IoTAgentNGSI.InMemoryGroupRegister'
|
|
@@ -131,31 +130,7 @@ function clear(callback) {
|
|
|
131
130
|
callback();
|
|
132
131
|
}
|
|
133
132
|
|
|
134
|
-
function findSingleConfigurationMode(service, subservice, callback) {
|
|
135
|
-
let result;
|
|
136
|
-
|
|
137
|
-
for (const i in registeredGroups) {
|
|
138
|
-
if (
|
|
139
|
-
registeredGroups.hasOwnProperty(i) &&
|
|
140
|
-
registeredGroups[i].service === service &&
|
|
141
|
-
registeredGroups[i].subservice === subservice
|
|
142
|
-
) {
|
|
143
|
-
result = registeredGroups[i];
|
|
144
|
-
break;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
if (result) {
|
|
149
|
-
callback(null, result);
|
|
150
|
-
} else {
|
|
151
|
-
callback(new errors.DeviceGroupNotFound(service, subservice));
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
133
|
function find(service, subservice, callback) {
|
|
156
|
-
if (config.getConfig().singleConfigurationMode === true) {
|
|
157
|
-
return findSingleConfigurationMode(service, subservice, callback);
|
|
158
|
-
}
|
|
159
134
|
const result = [];
|
|
160
135
|
|
|
161
136
|
for (const i in registeredGroups) {
|
|
@@ -58,7 +58,8 @@ const attributeList = [
|
|
|
58
58
|
'expressionLanguage',
|
|
59
59
|
'defaultEntityNameConjunction',
|
|
60
60
|
'ngsiVersion',
|
|
61
|
-
'entityNameExp'
|
|
61
|
+
'entityNameExp',
|
|
62
|
+
'payloadType'
|
|
62
63
|
];
|
|
63
64
|
|
|
64
65
|
/**
|
|
@@ -147,15 +148,15 @@ function listGroups(service, limit, offset, callback) {
|
|
|
147
148
|
query.skip(parseInt(offset, 10));
|
|
148
149
|
}
|
|
149
150
|
|
|
150
|
-
async.series(
|
|
151
|
-
|
|
152
|
-
results
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}
|
|
158
|
-
|
|
151
|
+
async.series(
|
|
152
|
+
[query.exec.bind(query), Group.model.countDocuments.bind(Group.model, condition)],
|
|
153
|
+
function (error, results) {
|
|
154
|
+
callback(error, {
|
|
155
|
+
count: results[1],
|
|
156
|
+
services: results[0].map(toObjectFn)
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
);
|
|
159
160
|
}
|
|
160
161
|
|
|
161
162
|
function getById(id, callback) {
|
|
@@ -201,15 +202,15 @@ function find(service, subservice, callback) {
|
|
|
201
202
|
|
|
202
203
|
const query = Group.model.find(condition).sort();
|
|
203
204
|
|
|
204
|
-
async.series(
|
|
205
|
-
|
|
206
|
-
results
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
}
|
|
212
|
-
|
|
205
|
+
async.series(
|
|
206
|
+
[query.exec.bind(query), Group.model.countDocuments.bind(Group.model, condition)],
|
|
207
|
+
function (error, results) {
|
|
208
|
+
callback(error, {
|
|
209
|
+
count: results[1],
|
|
210
|
+
services: results[0].map(toObjectFn)
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
);
|
|
213
214
|
}
|
|
214
215
|
|
|
215
216
|
function findOneInMongoDB(queryObj, fields, callback) {
|
|
@@ -59,10 +59,6 @@ function validateGroup(group, callback) {
|
|
|
59
59
|
config.getGroupRegistry().getSilently(group.resource, group.apikey, generateDuplicateHandler(innerCb));
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
function checkServiceAndSubservice(innerCb) {
|
|
63
|
-
config.getGroupRegistry().find(group.service, group.subservice, generateDuplicateHandler(innerCb));
|
|
64
|
-
}
|
|
65
|
-
|
|
66
62
|
function checkMandatoryParams(innerCb) {
|
|
67
63
|
if (!group.service) {
|
|
68
64
|
innerCb(new errors.MissingConfigParams(['service']));
|
|
@@ -74,22 +70,15 @@ function validateGroup(group, callback) {
|
|
|
74
70
|
return;
|
|
75
71
|
}
|
|
76
72
|
|
|
77
|
-
if (
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
73
|
+
if (!group.type) {
|
|
74
|
+
innerCb(new errors.MissingConfigParams(['type']));
|
|
75
|
+
return;
|
|
82
76
|
}
|
|
83
77
|
|
|
84
78
|
innerCb();
|
|
85
79
|
}
|
|
86
80
|
|
|
87
81
|
validations.push(checkApiKeyAndResource);
|
|
88
|
-
|
|
89
|
-
if (config.getConfig().singleConfigurationMode === true) {
|
|
90
|
-
validations.push(checkServiceAndSubservice);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
82
|
validations.push(checkMandatoryParams);
|
|
94
83
|
|
|
95
84
|
async.series(validations, callback);
|
|
@@ -41,11 +41,87 @@ const _ = require('underscore');
|
|
|
41
41
|
const context = {
|
|
42
42
|
op: 'IoTAgentNGSI-LD'
|
|
43
43
|
};
|
|
44
|
-
const NGSIv2 = require('./entities-NGSI-v2');
|
|
45
44
|
const NGSIUtils = require('./ngsiUtils');
|
|
46
45
|
|
|
47
46
|
const NGSI_LD_URN = 'urn:ngsi-ld:';
|
|
48
47
|
|
|
48
|
+
/**
|
|
49
|
+
* Adds timestamp to ngsi payload entities accoding to timezone, and an optional timestampvalue.
|
|
50
|
+
*
|
|
51
|
+
* @param {Object} payload NGSIv2 payload with one or more entities
|
|
52
|
+
* @param String timezone TimeZone value (optional)
|
|
53
|
+
* @param String timestampValue Timestamp value (optional). If not provided current timestamp is used
|
|
54
|
+
* @param Boolean skipMetadataAtt An optional flag to indicate if timestamp should be added to each metadata attribute. Default is false
|
|
55
|
+
* @return {Object} NGSIv2 payload entities with timestamp
|
|
56
|
+
*/
|
|
57
|
+
function addTimestamp(payload, timezone, timestampValue) {
|
|
58
|
+
function addTimestampEntity(entity, timezone, timestampValue) {
|
|
59
|
+
const timestamp = {
|
|
60
|
+
type: constants.TIMESTAMP_TYPE_NGSI2
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
if (timestampValue) {
|
|
64
|
+
timestamp.value = timestampValue;
|
|
65
|
+
} else if (!timezone) {
|
|
66
|
+
timestamp.value = new Date().toISOString();
|
|
67
|
+
} else {
|
|
68
|
+
timestamp.value = moment().tz(timezone).format('YYYY-MM-DD[T]HH:mm:ss.SSSZ');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function addMetadata(attribute) {
|
|
72
|
+
let timestampFound = false;
|
|
73
|
+
|
|
74
|
+
if (!attribute.metadata) {
|
|
75
|
+
attribute.metadata = {};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
for (let i = 0; i < attribute.metadata.length; i++) {
|
|
79
|
+
if (attribute.metadata[i] === constants.TIMESTAMP_ATTRIBUTE) {
|
|
80
|
+
if (
|
|
81
|
+
attribute.metadata[constants.TIMESTAMP_ATTRIBUTE].type === constants.TIMESTAMP_TYPE_NGSI2 &&
|
|
82
|
+
attribute.metadata[constants.TIMESTAMP_ATTRIBUTE].value === timestamp.value
|
|
83
|
+
) {
|
|
84
|
+
timestampFound = true;
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (!timestampFound) {
|
|
91
|
+
attribute.metadata[constants.TIMESTAMP_ATTRIBUTE] = timestamp;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return attribute;
|
|
95
|
+
}
|
|
96
|
+
let keyCount = 0;
|
|
97
|
+
for (const key in entity) {
|
|
98
|
+
/* eslint-disable-next-line no-prototype-builtins */
|
|
99
|
+
if (entity.hasOwnProperty(key) && key !== 'id' && key !== 'type') {
|
|
100
|
+
addMetadata(entity[key]);
|
|
101
|
+
keyCount += 1;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// Add timestamp just to entity with attrs: multientity plugin could
|
|
105
|
+
// create empty entities just with id and type.
|
|
106
|
+
if (keyCount > 0) {
|
|
107
|
+
entity[constants.TIMESTAMP_ATTRIBUTE] = timestamp;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return entity;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (payload instanceof Array) {
|
|
114
|
+
for (let i = 0; i < payload.length; i++) {
|
|
115
|
+
if (!utils.isTimestampedNgsi2(payload[i])) {
|
|
116
|
+
payload[i] = addTimestampEntity(payload[i], timezone, timestampValue);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return payload;
|
|
121
|
+
}
|
|
122
|
+
return addTimestampEntity(payload, timezone, timestampValue);
|
|
123
|
+
}
|
|
124
|
+
|
|
49
125
|
/**
|
|
50
126
|
* Amends an NGSIv2 attribute to NGSI-LD format
|
|
51
127
|
* All native JSON types are respected and cast as Property values
|
|
@@ -843,7 +919,7 @@ function sendUpdateValueNgsiLD(entityName, attributes, typeInformation, token, c
|
|
|
843
919
|
? config.getConfig().timestamp
|
|
844
920
|
: timestampValue !== undefined
|
|
845
921
|
) {
|
|
846
|
-
newEntity =
|
|
922
|
+
newEntity = addTimestamp(newEntity, typeInformation.timezone, timestampValue);
|
|
847
923
|
logger.debug(context, 'sendUpdateValueNgsiLD \n timestamped newEntity=%j', newEntity);
|
|
848
924
|
}
|
|
849
925
|
payload.push(newEntity);
|
|
@@ -927,19 +1003,19 @@ function sendUpdateValueNgsiLD(entityName, attributes, typeInformation, token, c
|
|
|
927
1003
|
// timeInstant is provided as measure
|
|
928
1004
|
if (Object.keys(payload[0]).length > 1) {
|
|
929
1005
|
// include metadata with TimeInstant in attrs when TimeInstant is provided as measure in all entities
|
|
930
|
-
payload[0] =
|
|
1006
|
+
payload[0] = addTimestamp(payload[0], typeInformation.timezone, timestampValue);
|
|
931
1007
|
}
|
|
932
1008
|
} else {
|
|
933
1009
|
// jshint maxdepth:5
|
|
934
1010
|
for (let n = 0; n < payload.length; n++) {
|
|
935
1011
|
if (!utils.isTimestampedNgsi2(payload[n])) {
|
|
936
1012
|
// legacy check needed?
|
|
937
|
-
payload[n] =
|
|
1013
|
+
payload[n] = addTimestamp(payload[n], typeInformation.timezone);
|
|
938
1014
|
// jshint maxdepth:5
|
|
939
1015
|
} else if (!utils.IsValidTimestampedNgsi2(payload[n])) {
|
|
940
1016
|
// legacy check needed?
|
|
941
1017
|
logger.error(context, 'Invalid timestamp:%s', JSON.stringify(payload[0]));
|
|
942
|
-
callback(new errors.BadTimestamp(payload));
|
|
1018
|
+
callback(new errors.BadTimestamp(payload, entityName));
|
|
943
1019
|
return;
|
|
944
1020
|
}
|
|
945
1021
|
}
|
|
@@ -955,9 +1031,8 @@ function sendUpdateValueNgsiLD(entityName, attributes, typeInformation, token, c
|
|
|
955
1031
|
delete payload[m][key].object_id;
|
|
956
1032
|
}
|
|
957
1033
|
}
|
|
958
|
-
payload[m] = NGSIUtils.castJsonNativeAttributes(payload[m]); // native types
|
|
959
1034
|
}
|
|
960
|
-
logger.debug(context, 'sendUpdateValueNgsiLD \n payload
|
|
1035
|
+
logger.debug(context, 'sendUpdateValueNgsiLD \n payload and without object_id %j', payload);
|
|
961
1036
|
|
|
962
1037
|
options.json = payload;
|
|
963
1038
|
try {
|