iotagent-node-lib 3.2.0 → 3.3.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/ISSUE_TEMPLATE/bug_report.yml +134 -0
- package/.github/ISSUE_TEMPLATE/config.yml +16 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +55 -0
- package/.github/advanced-issue-labeler.yml +30 -0
- package/.github/workflows/issue-labeler.yml +43 -0
- package/doc/api.md +23 -80
- package/doc/deprecated.md +4 -0
- package/doc/howto.md +58 -62
- package/doc/installationguide.md +0 -5
- package/doc/requirements.txt +1 -1
- package/docker/Mosquitto/Dockerfile +1 -1
- package/lib/model/Device.js +0 -1
- package/lib/model/Group.js +0 -1
- package/lib/model/dbConn.js +1 -7
- package/lib/plugins/jexlParser.js +1 -1
- package/lib/services/common/iotManagerService.js +0 -1
- package/lib/services/devices/deviceRegistryMongoDB.js +10 -10
- package/lib/services/devices/deviceService.js +14 -19
- package/lib/services/devices/devices-NGSI-v2.js +2 -5
- package/lib/services/ngsi/entities-NGSI-LD.js +3 -3
- package/lib/services/ngsi/entities-NGSI-v2.js +34 -11
- package/lib/services/northBound/deviceProvisioningServer.js +0 -3
- package/lib/templates/createDevice.json +0 -4
- package/lib/templates/createDeviceLax.json +0 -4
- package/lib/templates/deviceGroup.json +1 -5
- package/lib/templates/updateDevice.json +4 -0
- package/lib/templates/updateDeviceLax.json +11 -0
- package/package.json +1 -1
- package/scripts/legacy_expression_tool/README.md +262 -0
- package/scripts/legacy_expression_tool/legacy_expression_tool.py +423 -0
- package/scripts/legacy_expression_tool/requirements.txt +3 -0
- package/test/unit/examples/deviceProvisioningRequests/provisionMinimumDevice4.json +0 -1
- package/test/unit/general/contextBrokerKeystoneSecurityAccess-test.js +3 -13
- package/test/unit/ngsi-ld/lazyAndCommands/merge-patch-test.js +31 -30
- package/test/unit/ngsi-mixed/provisioning/ngsi-versioning-test.js +33 -37
- package/test/unit/ngsiv2/examples/contextRequests/updateContext.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContext1.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContext3WithStatic.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContext4.json +4 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContext5.json +12 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContext6.json +10 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin1.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin2.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin3.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin4.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin5.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin6.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin7.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin8.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin9.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast1.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast2.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast3.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast4.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast5.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast6.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast7.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextCommandError.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextCommandExpired.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextCommandFinish.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextCommandStatus.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextCommandStatus2.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextCompressTimestamp1.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextCompressTimestamp2.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin1.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin11.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin12.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin13.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin2.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin29.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin3.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin30.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin31.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin32.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin33.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin34.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin35.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin36.json +1 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin4.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin40.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin41.json +1 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin5.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin6.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin7.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin8.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin9.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionSkip.json +12 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityJexlExpressionPlugin1.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin1.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin10.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin11.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin12.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin13.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin14.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin15.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin16.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin17.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin2.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin25.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin3.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin4.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin5.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin6.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin7.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin8.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin9.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin1.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin2.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin3.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin4.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextProcessTimestamp.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextStaticAttributes.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextStaticAttributesMetadata.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextTimestamp.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextTimestampFalse.json +12 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextTimestampFalseTimeInstant.json +12 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextTimestampOverride.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextTimestampOverrideWithoutMilis.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextTimestampTimezone.json +3 -1
- package/test/unit/ngsiv2/expressions/jexlBasedTransformations-test.js +133 -75
- package/test/unit/ngsiv2/general/contextBrokerOAuthSecurityAccess-test.js +18 -51
- package/test/unit/ngsiv2/general/https-support-test.js +1 -5
- package/test/unit/ngsiv2/lazyAndCommands/command-test.js +4 -10
- package/test/unit/ngsiv2/lazyAndCommands/polling-commands-test.js +8 -24
- package/test/unit/ngsiv2/ngsiService/active-devices-test.js +143 -57
- package/test/unit/ngsiv2/ngsiService/autocast-test.js +14 -21
- package/test/unit/ngsiv2/ngsiService/staticAttributes-test.js +3 -5
- package/test/unit/ngsiv2/ngsiService/subscriptions-test.js +1 -10
- package/test/unit/ngsiv2/plugins/alias-plugin_test.js +20 -30
- package/test/unit/ngsiv2/plugins/bidirectional-plugin_test.js +0 -63
- package/test/unit/ngsiv2/plugins/compress-timestamp-plugin_test.js +4 -6
- package/test/unit/ngsiv2/plugins/custom-plugin_test.js +1 -2
- package/test/unit/ngsiv2/plugins/multientity-plugin_test.js +3 -5
- package/test/unit/ngsiv2/plugins/timestamp-processing-plugin_test.js +2 -3
- package/test/unit/ngsiv2/provisioning/device-group-api-test.js +2 -3
- package/test/unit/ngsiv2/provisioning/device-provisioning-api_test.js +5 -53
- package/test/unit/ngsiv2/provisioning/device-registration_test.js +1 -7
- package/test/unit/ngsiv2/provisioning/device-update-registration_test.js +2 -9
- package/test/unit/ngsiv2/provisioning/singleConfigurationMode-test.js +0 -11
- package/test/unit/ngsiv2/provisioning/updateProvisionedDevices-test.js +0 -7
- package/test/unit/plugins/capture-provision-inPlugins_test.js +0 -6
package/doc/howto.md
CHANGED
|
@@ -75,12 +75,12 @@ folder of your project. Remember to change the Context Broker IP to your local C
|
|
|
75
75
|
Now we can begin with the code of our IoT Agent. The very minimum code we need to start an IoT Agent is the following:
|
|
76
76
|
|
|
77
77
|
```javascript
|
|
78
|
-
var iotAgentLib = require(
|
|
79
|
-
config = require(
|
|
78
|
+
var iotAgentLib = require('iotagent-node-lib'),
|
|
79
|
+
config = require('./config');
|
|
80
80
|
|
|
81
81
|
iotAgentLib.activate(config, function (error) {
|
|
82
82
|
if (error) {
|
|
83
|
-
console.log(
|
|
83
|
+
console.log('There was an error activating the IOTA');
|
|
84
84
|
process.exit(1);
|
|
85
85
|
}
|
|
86
86
|
});
|
|
@@ -112,10 +112,10 @@ In order to add the Express dependency to your project, add the following line t
|
|
|
112
112
|
The require section would end up like this (the standard `http` module is also needed):
|
|
113
113
|
|
|
114
114
|
```javascript
|
|
115
|
-
var iotAgentLib = require(
|
|
116
|
-
http = require(
|
|
117
|
-
express = require(
|
|
118
|
-
config = require(
|
|
115
|
+
var iotAgentLib = require('iotagent-node-lib'),
|
|
116
|
+
http = require('http'),
|
|
117
|
+
express = require('express'),
|
|
118
|
+
config = require('./config');
|
|
119
119
|
```
|
|
120
120
|
|
|
121
121
|
And install the dependencies as usual with `npm install`. You will have to require both `express` and `http` in your
|
|
@@ -129,16 +129,16 @@ function initSouthbound(callback) {
|
|
|
129
129
|
southboundServer = {
|
|
130
130
|
server: null,
|
|
131
131
|
app: express(),
|
|
132
|
-
router: express.Router()
|
|
132
|
+
router: express.Router()
|
|
133
133
|
};
|
|
134
134
|
|
|
135
|
-
southboundServer.app.set(
|
|
136
|
-
southboundServer.app.set(
|
|
135
|
+
southboundServer.app.set('port', 8080);
|
|
136
|
+
southboundServer.app.set('host', '0.0.0.0');
|
|
137
137
|
|
|
138
|
-
southboundServer.router.get(
|
|
138
|
+
southboundServer.router.get('/iot/d', manageULRequest);
|
|
139
139
|
southboundServer.server = http.createServer(southboundServer.app);
|
|
140
|
-
southboundServer.app.use(
|
|
141
|
-
southboundServer.server.listen(southboundServer.app.get(
|
|
140
|
+
southboundServer.app.use('/', southboundServer.router);
|
|
141
|
+
southboundServer.server.listen(southboundServer.app.get('port'), southboundServer.app.get('host'), callback);
|
|
142
142
|
}
|
|
143
143
|
```
|
|
144
144
|
|
|
@@ -154,18 +154,18 @@ function manageULRequest(req, res, next) {
|
|
|
154
154
|
iotAgentLib.retrieveDevice(req.query.i, req.query.k, function (error, device) {
|
|
155
155
|
if (error) {
|
|
156
156
|
res.status(404).send({
|
|
157
|
-
message: "Couldn't find the device: " + JSON.stringify(error)
|
|
157
|
+
message: "Couldn't find the device: " + JSON.stringify(error)
|
|
158
158
|
});
|
|
159
159
|
} else {
|
|
160
160
|
values = parseUl(req.query.d, device);
|
|
161
|
-
iotAgentLib.update(device.name, device.type,
|
|
161
|
+
iotAgentLib.update(device.name, device.type, '', values, device, function (error) {
|
|
162
162
|
if (error) {
|
|
163
163
|
res.status(500).send({
|
|
164
|
-
message:
|
|
164
|
+
message: 'Error updating the device'
|
|
165
165
|
});
|
|
166
166
|
} else {
|
|
167
167
|
res.status(200).send({
|
|
168
|
-
message:
|
|
168
|
+
message: 'Device successfully updated'
|
|
169
169
|
});
|
|
170
170
|
}
|
|
171
171
|
});
|
|
@@ -190,17 +190,17 @@ function parseUl(data, device) {
|
|
|
190
190
|
}
|
|
191
191
|
|
|
192
192
|
function createAttribute(element) {
|
|
193
|
-
var pair = element.split(
|
|
193
|
+
var pair = element.split('|'),
|
|
194
194
|
attribute = {
|
|
195
195
|
name: pair[0],
|
|
196
196
|
value: pair[1],
|
|
197
|
-
type: findType(pair[0])
|
|
197
|
+
type: findType(pair[0])
|
|
198
198
|
};
|
|
199
199
|
|
|
200
200
|
return attribute;
|
|
201
201
|
}
|
|
202
202
|
|
|
203
|
-
return data.split(
|
|
203
|
+
return data.split(',').map(createAttribute);
|
|
204
204
|
}
|
|
205
205
|
```
|
|
206
206
|
|
|
@@ -227,14 +227,14 @@ show the modifications in the `activate()` function:
|
|
|
227
227
|
```javascript
|
|
228
228
|
iotAgentLib.activate(config, function (error) {
|
|
229
229
|
if (error) {
|
|
230
|
-
console.log(
|
|
230
|
+
console.log('There was an error activating the IOTA');
|
|
231
231
|
process.exit(1);
|
|
232
232
|
} else {
|
|
233
233
|
initSouthbound(function (error) {
|
|
234
234
|
if (error) {
|
|
235
|
-
console.log(
|
|
235
|
+
console.log('Could not initialize South bound API due to the following error: %s', error);
|
|
236
236
|
} else {
|
|
237
|
-
console.log(
|
|
237
|
+
console.log('Both APIs started successfully');
|
|
238
238
|
}
|
|
239
239
|
});
|
|
240
240
|
}
|
|
@@ -286,7 +286,7 @@ A HTTP request library will be needed in order to make those calls. To this exte
|
|
|
286
286
|
used. In order to do so, add the following require statement to the initialization code:
|
|
287
287
|
|
|
288
288
|
```javascript
|
|
289
|
-
request = require(
|
|
289
|
+
request = require('request');
|
|
290
290
|
```
|
|
291
291
|
|
|
292
292
|
and add the `request` dependency to the `package.json` file:
|
|
@@ -303,11 +303,11 @@ and add the `request` dependency to the `package.json` file:
|
|
|
303
303
|
The require section should now look like this:
|
|
304
304
|
|
|
305
305
|
```javascript
|
|
306
|
-
var iotAgentLib = require(
|
|
307
|
-
http = require(
|
|
308
|
-
express = require(
|
|
309
|
-
request = require(
|
|
310
|
-
config = require(
|
|
306
|
+
var iotAgentLib = require('iotagent-node-lib'),
|
|
307
|
+
http = require('http'),
|
|
308
|
+
express = require('express'),
|
|
309
|
+
request = require('request'),
|
|
310
|
+
config = require('./config');
|
|
311
311
|
```
|
|
312
312
|
|
|
313
313
|
### Implementation
|
|
@@ -321,11 +321,11 @@ for the context provisioning requests. At this point, we should provide two hand
|
|
|
321
321
|
```javascript
|
|
322
322
|
function queryContextHandler(id, type, service, subservice, attributes, callback) {
|
|
323
323
|
var options = {
|
|
324
|
-
url:
|
|
325
|
-
method:
|
|
324
|
+
url: 'http://127.0.0.1:9999/iot/d',
|
|
325
|
+
method: 'GET',
|
|
326
326
|
qs: {
|
|
327
|
-
q: attributes.join()
|
|
328
|
-
}
|
|
327
|
+
q: attributes.join()
|
|
328
|
+
}
|
|
329
329
|
};
|
|
330
330
|
|
|
331
331
|
request(options, function (error, response, body) {
|
|
@@ -350,21 +350,21 @@ attributes). Here is the code for the `createResponse()` function:
|
|
|
350
350
|
|
|
351
351
|
```javascript
|
|
352
352
|
function createResponse(id, type, attributes, body) {
|
|
353
|
-
var values = body.split(
|
|
353
|
+
var values = body.split(','),
|
|
354
354
|
responses = [];
|
|
355
355
|
|
|
356
356
|
for (var i = 0; i < attributes.length; i++) {
|
|
357
357
|
responses.push({
|
|
358
358
|
name: attributes[i],
|
|
359
|
-
type:
|
|
360
|
-
value: values[i]
|
|
359
|
+
type: 'string',
|
|
360
|
+
value: values[i]
|
|
361
361
|
});
|
|
362
362
|
}
|
|
363
363
|
|
|
364
364
|
return {
|
|
365
365
|
id: id,
|
|
366
366
|
type: type,
|
|
367
|
-
attributes: responses
|
|
367
|
+
attributes: responses
|
|
368
368
|
};
|
|
369
369
|
}
|
|
370
370
|
```
|
|
@@ -374,11 +374,11 @@ function createResponse(id, type, attributes, body) {
|
|
|
374
374
|
```javascript
|
|
375
375
|
function updateContextHandler(id, type, service, subservice, attributes, callback) {
|
|
376
376
|
var options = {
|
|
377
|
-
url:
|
|
378
|
-
method:
|
|
377
|
+
url: 'http://127.0.0.1:9999/iot/d',
|
|
378
|
+
method: 'GET',
|
|
379
379
|
qs: {
|
|
380
|
-
d: createQueryFromAttributes(attributes)
|
|
381
|
-
}
|
|
380
|
+
d: createQueryFromAttributes(attributes)
|
|
381
|
+
}
|
|
382
382
|
};
|
|
383
383
|
|
|
384
384
|
request(options, function (error, response, body) {
|
|
@@ -388,31 +388,31 @@ function updateContextHandler(id, type, service, subservice, attributes, callbac
|
|
|
388
388
|
callback(null, {
|
|
389
389
|
id: id,
|
|
390
390
|
type: type,
|
|
391
|
-
attributes: attributes
|
|
391
|
+
attributes: attributes
|
|
392
392
|
});
|
|
393
393
|
}
|
|
394
394
|
});
|
|
395
395
|
}
|
|
396
396
|
```
|
|
397
397
|
|
|
398
|
-
The updateContext handler deals with the modification requests that arrive at the North Port of the IoT Agent via
|
|
399
|
-
invoked once for each entity requested (note that a single request can contain multiple entity
|
|
400
|
-
parameters used in the queryContext handler. The only difference is the value of the attributes
|
|
401
|
-
list of attribute objects, each containing name, type and value. The handler must also make use
|
|
402
|
-
return a list of updated attributes.
|
|
398
|
+
The updateContext handler deals with the modification requests that arrive at the North Port of the IoT Agent via
|
|
399
|
+
`/v2/op/update`. It is invoked once for each entity requested (note that a single request can contain multiple entity
|
|
400
|
+
updates), with the same parameters used in the queryContext handler. The only difference is the value of the attributes
|
|
401
|
+
array, now containing a list of attribute objects, each containing name, type and value. The handler must also make use
|
|
402
|
+
of the callback to return a list of updated attributes.
|
|
403
403
|
|
|
404
404
|
For this handler we have used a helper function called `createQueryFromAttributes()`, that transforms the NGSI
|
|
405
405
|
representation of the attributes to the UL type expected by the device:
|
|
406
406
|
|
|
407
407
|
```javascript
|
|
408
408
|
function createQueryFromAttributes(attributes) {
|
|
409
|
-
var query =
|
|
409
|
+
var query = '';
|
|
410
410
|
|
|
411
411
|
for (var i in attributes) {
|
|
412
|
-
query += attributes[i].name +
|
|
412
|
+
query += attributes[i].name + '|' + attributes[i].value;
|
|
413
413
|
|
|
414
414
|
if (i != attributes.length - 1) {
|
|
415
|
-
query +=
|
|
415
|
+
query += ',';
|
|
416
416
|
}
|
|
417
417
|
}
|
|
418
418
|
|
|
@@ -544,10 +544,6 @@ request/seconds that can be manage by the server. It's important to remark that
|
|
|
544
544
|
included in the IoT Agent Node Lib but it is not mandatory that you activate this functionality. In this example, we
|
|
545
545
|
will see how to use this functionality to deploy an IoT Agent in multi-thread environment.
|
|
546
546
|
|
|
547
|
-
**WARNING:** it has been observed in Orion-IOTA integration tests some fails in bidirectional plugin usage scenarios in
|
|
548
|
-
multi-thread mode. The fail has not been confirmed yet (it could be a glitch of the testing environment). However, take
|
|
549
|
-
this into account if you use multi-thread in combination with bidirectional plugin.
|
|
550
|
-
|
|
551
547
|
In order to activate the functionality, you have two options, configure the `config.js` file to add the following line:
|
|
552
548
|
|
|
553
549
|
```javascript
|
|
@@ -563,9 +559,9 @@ variable and afterward the value of the multiCore in the `config.js` file. The r
|
|
|
563
559
|
(the standard `http` module is also needed):
|
|
564
560
|
|
|
565
561
|
```javascript
|
|
566
|
-
var iotAgent = require(
|
|
567
|
-
iotAgentLib = require(
|
|
568
|
-
config = require(
|
|
562
|
+
var iotAgent = require('../lib/iotagent-implementation'),
|
|
563
|
+
iotAgentLib = require('iotagent-node-lib'),
|
|
564
|
+
config = require('./config');
|
|
569
565
|
```
|
|
570
566
|
|
|
571
567
|
It is important to mention the purpose of the `iotAgent` variable. It is the proper implementation of the IoT Agent
|
|
@@ -581,9 +577,9 @@ about starting the IoTAgent:
|
|
|
581
577
|
```javascript
|
|
582
578
|
iotAgentLib.startServer(config, iotAgent, function (error) {
|
|
583
579
|
if (error) {
|
|
584
|
-
console.log(context,
|
|
580
|
+
console.log(context, 'Error starting IoT Agent: [%s] Exiting process', error);
|
|
585
581
|
} else {
|
|
586
|
-
console.log(context,
|
|
582
|
+
console.log(context, 'IoT Agent started');
|
|
587
583
|
}
|
|
588
584
|
});
|
|
589
585
|
```
|
|
@@ -610,7 +606,7 @@ handlers themselves. Here we can see the definition of the configuration handler
|
|
|
610
606
|
|
|
611
607
|
```javascript
|
|
612
608
|
function configurationHandler(configuration, callback) {
|
|
613
|
-
console.log(
|
|
609
|
+
console.log('\n\n* REGISTERING A NEW CONFIGURATION:\n%s\n\n', JSON.stringify(configuration, null, 4));
|
|
614
610
|
callback(null, configuration);
|
|
615
611
|
}
|
|
616
612
|
```
|
|
@@ -627,8 +623,8 @@ feature, let's use the provisioning handler to change the value of the type of t
|
|
|
627
623
|
|
|
628
624
|
```javascript
|
|
629
625
|
function provisioningHandler(device, callback) {
|
|
630
|
-
console.log(
|
|
631
|
-
device.type =
|
|
626
|
+
console.log('\n\n* REGISTERING A NEW DEVICE:\n%s\n\n', JSON.stringify(device, null, 4));
|
|
627
|
+
device.type = 'CertifiedType';
|
|
632
628
|
callback(null, device);
|
|
633
629
|
}
|
|
634
630
|
```
|
package/doc/installationguide.md
CHANGED
|
@@ -249,10 +249,6 @@ used for the same purpose. For instance:
|
|
|
249
249
|
'http://192.168.56.1:4041'.
|
|
250
250
|
- **iotaVersion**: indicates the version of the IoTA that will be displayed in the about method (it should be filled
|
|
251
251
|
automatically by each IoTA).
|
|
252
|
-
- **appendMode**: if this flag is activated, the update requests to the Context Broker will be performed always with
|
|
253
|
-
APPEND type, instead of the default UPDATE. This have implications in the use of attributes with Context Providers,
|
|
254
|
-
so this flag should be used with care. This flag is overwritten by `autoprovision` flag in group or device
|
|
255
|
-
provision.
|
|
256
252
|
- **dieOnUnexpectedError**: if this flag is activated, the IoTAgent will not capture global exception, thus dying upon
|
|
257
253
|
any unexpected error.
|
|
258
254
|
- **singleConfigurationMode**: enables the Single Configuration mode for backwards compatibility (see description in
|
|
@@ -352,7 +348,6 @@ overrides.
|
|
|
352
348
|
| IOTA_MONGO_SSL | `mongodb.ssl` |
|
|
353
349
|
| IOTA_MONGO_EXTRAARGS | `mongodb.extraArgs` |
|
|
354
350
|
| IOTA_SINGLE_MODE | `singleConfigurationMode` |
|
|
355
|
-
| IOTA_APPEND_MODE | `appendMode` |
|
|
356
351
|
| IOTA_POLLING_EXPIRATION | `pollingExpiration` |
|
|
357
352
|
| IOTA_POLLING_DAEMON_FREQ | `pollingDaemonFrequency` |
|
|
358
353
|
| IOTA_AUTOCAST | `autocast` |
|
package/doc/requirements.txt
CHANGED
package/lib/model/Device.js
CHANGED
package/lib/model/Group.js
CHANGED
package/lib/model/dbConn.js
CHANGED
|
@@ -106,13 +106,7 @@ function init(host, db, port, options, callback) {
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
function connectionAttempt(url, options, callback) {
|
|
109
|
-
logger.info(
|
|
110
|
-
context,
|
|
111
|
-
'Attempting to connect to MongoDB instance with url %j and options %j. Attempt %d',
|
|
112
|
-
url,
|
|
113
|
-
options,
|
|
114
|
-
retries
|
|
115
|
-
);
|
|
109
|
+
logger.info(context, 'Attempting to connect to MongoDB instance with url %j. Attempt %d', url, retries);
|
|
116
110
|
// FIXME: useNewUrlParser is no longer used in underlying mongodb driver 4.x
|
|
117
111
|
// (see https://github.com/mongodb/node-mongodb-native/blob/HEAD/etc/notes/CHANGES_4.0.0.md)
|
|
118
112
|
// but not sure if current mongoose version is still using mongodb 3.x internally
|
|
@@ -77,7 +77,7 @@ function extractVariables(expression) {
|
|
|
77
77
|
variables = tokens.filter(function (token, index, array) {
|
|
78
78
|
return (
|
|
79
79
|
(token.type === ' ' && array[index - 1].type !== 'dot') ||
|
|
80
|
-
(token.type === 'identifier' && array[index + 1].type !== 'openParen')
|
|
80
|
+
(token.type === 'identifier' && array[index + 1] && array[index + 1].type !== 'openParen')
|
|
81
81
|
);
|
|
82
82
|
});
|
|
83
83
|
|
|
@@ -58,7 +58,6 @@ function register(callback) {
|
|
|
58
58
|
timestamp: service.timestamp,
|
|
59
59
|
autoprovision: service.autoprovision,
|
|
60
60
|
explicitAttrs: service.explicitAttrs,
|
|
61
|
-
expressionLanguage: service.expressionLanguage,
|
|
62
61
|
defaultEntityNameConjunction: service.defaultEntityNameConjunction,
|
|
63
62
|
ngsiVersion: service.ngsiVersion,
|
|
64
63
|
entityNameExp: service.entityNameExp
|
|
@@ -55,7 +55,6 @@ const attributeList = [
|
|
|
55
55
|
'polling',
|
|
56
56
|
'timestamp',
|
|
57
57
|
'explicitAttrs',
|
|
58
|
-
'expressionLanguage',
|
|
59
58
|
'ngsiVersion'
|
|
60
59
|
];
|
|
61
60
|
|
|
@@ -176,15 +175,15 @@ function listDevices(type, service, subservice, limit, offset, callback) {
|
|
|
176
175
|
query.skip(parseInt(offset, 10));
|
|
177
176
|
}
|
|
178
177
|
|
|
179
|
-
async.series(
|
|
180
|
-
|
|
181
|
-
results
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}
|
|
187
|
-
|
|
178
|
+
async.series(
|
|
179
|
+
[query.exec.bind(query), Device.model.countDocuments.bind(Device.model, condition)],
|
|
180
|
+
function (error, results) {
|
|
181
|
+
callback(error, {
|
|
182
|
+
count: results[1],
|
|
183
|
+
devices: results[0]
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
);
|
|
188
187
|
}
|
|
189
188
|
|
|
190
189
|
function findOneInMongoDB(queryParams, id, callback) {
|
|
@@ -303,6 +302,7 @@ function update(device, callback) {
|
|
|
303
302
|
data.registrationId = device.registrationId;
|
|
304
303
|
data.explicitAttrs = device.explicitAttrs;
|
|
305
304
|
data.ngsiVersion = device.ngsiVersion;
|
|
305
|
+
data.timestamp = device.timestamp;
|
|
306
306
|
|
|
307
307
|
/* eslint-disable-next-line new-cap */
|
|
308
308
|
const deviceObj = new Device.model(data);
|
|
@@ -72,7 +72,12 @@ function init() {
|
|
|
72
72
|
* @param {Object} newDevice Device object that will be stored in the database.
|
|
73
73
|
*/
|
|
74
74
|
function createInitialEntity(deviceData, newDevice, callback) {
|
|
75
|
-
|
|
75
|
+
if (config.getConfig().appendMode === false || config.ngsiVersion() === 'ld' || deviceData.ngsiVersion === 'ld') {
|
|
76
|
+
deviceHandler.createInitialEntity(deviceData, newDevice, callback);
|
|
77
|
+
} else {
|
|
78
|
+
logger.debug(context, 'Skip create initial entity due appendMode is false or ngsiLD.');
|
|
79
|
+
callback(null, newDevice);
|
|
80
|
+
}
|
|
76
81
|
}
|
|
77
82
|
|
|
78
83
|
/**
|
|
@@ -178,13 +183,12 @@ function mergeDeviceWithConfiguration(fields, defaults, deviceData, configuratio
|
|
|
178
183
|
if (configuration && configuration.ngsiVersion) {
|
|
179
184
|
deviceData.ngsiVersion = configuration.ngsiVersion;
|
|
180
185
|
}
|
|
181
|
-
if (configuration && configuration.expressionLanguage && deviceData.expressionLanguage === undefined) {
|
|
182
|
-
deviceData.expressionLanguage = configuration.expressionLanguage;
|
|
183
|
-
}
|
|
184
186
|
if (configuration && configuration.explicitAttrs !== undefined && deviceData.explicitAttrs === undefined) {
|
|
185
187
|
deviceData.explicitAttrs = configuration.explicitAttrs;
|
|
186
188
|
}
|
|
187
|
-
|
|
189
|
+
if (configuration && configuration.entityNameExp !== undefined) {
|
|
190
|
+
deviceData.entityNameExp = configuration.entityNameExp;
|
|
191
|
+
}
|
|
188
192
|
logger.debug(context, 'deviceData after merge with conf: %j', deviceData);
|
|
189
193
|
callback(null, deviceData);
|
|
190
194
|
}
|
|
@@ -265,7 +269,7 @@ function registerDevice(deviceObj, callback) {
|
|
|
265
269
|
function prepareDeviceData(deviceObj, configuration, callback) {
|
|
266
270
|
const deviceData = _.clone(deviceObj);
|
|
267
271
|
let selectedConfiguration;
|
|
268
|
-
|
|
272
|
+
logger.debug(context, 'Prepare device data:\n%s', JSON.stringify(deviceData, null, 4));
|
|
269
273
|
if (!deviceData.type) {
|
|
270
274
|
if (configuration && configuration.type) {
|
|
271
275
|
deviceData.type = configuration.type;
|
|
@@ -362,9 +366,9 @@ function registerDevice(deviceObj, callback) {
|
|
|
362
366
|
deviceObj.service = deviceData.service;
|
|
363
367
|
deviceObj.subservice = deviceData.subservice;
|
|
364
368
|
deviceObj.type = deviceData.type;
|
|
365
|
-
deviceObj.staticAttributes =
|
|
366
|
-
deviceObj.commands =
|
|
367
|
-
deviceObj.lazy =
|
|
369
|
+
deviceObj.staticAttributes = deviceObj.staticAttributes ? deviceObj.staticAttributes : [];
|
|
370
|
+
deviceObj.commands = deviceObj.commands ? deviceObj.commands : [];
|
|
371
|
+
deviceObj.lazy = deviceObj.lazy ? deviceObj.lazy : [];
|
|
368
372
|
if ('timestamp' in deviceData && deviceData.timestamp !== undefined) {
|
|
369
373
|
deviceObj.timestamp = deviceData.timestamp;
|
|
370
374
|
}
|
|
@@ -374,6 +378,7 @@ function registerDevice(deviceObj, callback) {
|
|
|
374
378
|
if ('apikey' in deviceData && deviceData.apikey !== undefined) {
|
|
375
379
|
deviceObj.apikey = deviceData.apikey;
|
|
376
380
|
}
|
|
381
|
+
logger.debug(context, 'Storing device :\n%s', JSON.stringify(deviceObj, null, 4));
|
|
377
382
|
config.getRegistry().store(deviceObj, callback);
|
|
378
383
|
}
|
|
379
384
|
}
|
|
@@ -618,19 +623,9 @@ function findOrCreate(deviceId, group, callback) {
|
|
|
618
623
|
if (config.getConfig().iotManager && config.getConfig().iotManager.protocol) {
|
|
619
624
|
newDevice.protocol = config.getConfig().iotManager.protocol;
|
|
620
625
|
}
|
|
621
|
-
|
|
622
|
-
if ('timestamp' in group && group.timestamp !== undefined) {
|
|
623
|
-
newDevice.timestamp = group.timestamp;
|
|
624
|
-
}
|
|
625
626
|
if ('ngsiVersion' in group && group.ngsiVersion !== undefined) {
|
|
626
627
|
newDevice.ngsiVersion = group.ngsiVersion;
|
|
627
628
|
}
|
|
628
|
-
if ('explicitAttrs' in group && group.explicitAttrs !== undefined) {
|
|
629
|
-
newDevice.explicitAttrs = group.explicitAttrs;
|
|
630
|
-
}
|
|
631
|
-
if ('expressionLanguage' in group && group.expressionLanguage !== undefined) {
|
|
632
|
-
newDevice.expressionLanguage = group.expressionLanguage;
|
|
633
|
-
}
|
|
634
629
|
if (
|
|
635
630
|
(!('apikey' in newDevice) || newDevice.apikey === undefined) &&
|
|
636
631
|
'apikey' in group &&
|
|
@@ -240,7 +240,7 @@ function createInitialEntityNgsi2(deviceData, newDevice, callback) {
|
|
|
240
240
|
}
|
|
241
241
|
}
|
|
242
242
|
|
|
243
|
-
logger.debug(context, 'deviceData: %j', deviceData);
|
|
243
|
+
logger.debug(context, 'Creating initial entity with deviceData: %j', deviceData);
|
|
244
244
|
if (
|
|
245
245
|
('timestamp' in deviceData && deviceData.timestamp !== undefined
|
|
246
246
|
? deviceData.timestamp
|
|
@@ -356,11 +356,8 @@ function updateRegisterDeviceNgsi2(deviceObj, entityInfoUpdated, callback) {
|
|
|
356
356
|
if ('explicitAttrs' in newDevice && newDevice.explicitAttrs !== undefined) {
|
|
357
357
|
oldDevice.explicitAttrs = newDevice.explicitAttrs;
|
|
358
358
|
}
|
|
359
|
-
if ('expressionLanguage' in newDevice && newDevice.expressionLanguage !== undefined) {
|
|
360
|
-
oldDevice.expressionLanguage = newDevice.expressionLanguage;
|
|
361
|
-
}
|
|
362
359
|
if ('apikey' in newDevice && newDevice.apikey !== undefined) {
|
|
363
|
-
oldDevice.
|
|
360
|
+
oldDevice.apikey = newDevice.apikey;
|
|
364
361
|
}
|
|
365
362
|
oldDevice.endpoint = newDevice.endpoint || oldDevice.endpoint;
|
|
366
363
|
|
|
@@ -439,10 +439,10 @@ function sendUpdateValueNgsiLD(entityName, attributes, typeInformation, token, c
|
|
|
439
439
|
payload[0].type = typeInformation.type;
|
|
440
440
|
}
|
|
441
441
|
|
|
442
|
-
if (config.getConfig().appendMode ===
|
|
443
|
-
payload.actionType = 'append';
|
|
444
|
-
} else {
|
|
442
|
+
if (config.getConfig().appendMode === false) {
|
|
445
443
|
payload.actionType = 'update';
|
|
444
|
+
} else {
|
|
445
|
+
payload.actionType = 'append';
|
|
446
446
|
}
|
|
447
447
|
|
|
448
448
|
const options = NGSIUtils.createRequestObject(url, typeInformation, token);
|
|
@@ -354,10 +354,10 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca
|
|
|
354
354
|
payload.entities[0].type = typeInformation.type;
|
|
355
355
|
}
|
|
356
356
|
|
|
357
|
-
if (config.getConfig().appendMode ===
|
|
358
|
-
payload.actionType = 'append';
|
|
359
|
-
} else {
|
|
357
|
+
if (config.getConfig().appendMode === false) {
|
|
360
358
|
payload.actionType = 'update';
|
|
359
|
+
} else {
|
|
360
|
+
payload.actionType = 'append';
|
|
361
361
|
}
|
|
362
362
|
|
|
363
363
|
let options = NGSIUtils.createRequestObject(url, typeInformation, token);
|
|
@@ -675,6 +675,23 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca
|
|
|
675
675
|
}
|
|
676
676
|
}
|
|
677
677
|
|
|
678
|
+
// Evaluate entityNameExp with a context including measures
|
|
679
|
+
if (typeInformation.entityNameExp !== undefined && typeInformation.entityNameExp !== '') {
|
|
680
|
+
try {
|
|
681
|
+
logger.debug(context, 'sendUpdateValueNgsi2 entityNameExp %j ', typeInformation.entityNameExp);
|
|
682
|
+
entityName = expressionPlugin.applyExpression(typeInformation.entityNameExp, ctxt, typeInformation);
|
|
683
|
+
payload.entities[0].id = entityName;
|
|
684
|
+
ctxt['entity_name'] = entityName;
|
|
685
|
+
} catch (e) {
|
|
686
|
+
logger.debug(
|
|
687
|
+
context,
|
|
688
|
+
'Error evaluating expression for entityName: %s with context: %s',
|
|
689
|
+
typeInformation.entityNameExp,
|
|
690
|
+
ctxt
|
|
691
|
+
);
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
|
|
678
695
|
logger.debug(context, 'sendUpdateValueNgsi2 currentEntity sorted %j ', currentEntity);
|
|
679
696
|
let timestampValue = undefined;
|
|
680
697
|
// Loop for each final attribute to apply alias, multientity and expressions
|
|
@@ -970,18 +987,24 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca
|
|
|
970
987
|
// only in the first case
|
|
971
988
|
if (options.json.entities.length === 1) {
|
|
972
989
|
// recreate options object to use single entity update
|
|
973
|
-
url = '/v2/entities
|
|
974
|
-
if (
|
|
975
|
-
url += '
|
|
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';
|
|
976
999
|
}
|
|
977
1000
|
options = NGSIUtils.createRequestObject(url, typeInformation, token);
|
|
978
1001
|
options.json = payload.entities[0];
|
|
979
|
-
|
|
980
|
-
delete options.json.type;
|
|
981
|
-
if (config.getConfig().appendMode === true) {
|
|
982
|
-
options.method = 'POST';
|
|
983
|
-
} else {
|
|
1002
|
+
if (config.getConfig().appendMode === false) {
|
|
984
1003
|
options.method = 'PATCH';
|
|
1004
|
+
delete options.json.id;
|
|
1005
|
+
delete options.json.type;
|
|
1006
|
+
} else {
|
|
1007
|
+
options.method = 'POST';
|
|
985
1008
|
}
|
|
986
1009
|
} // else: keep current options object created for a batch update
|
|
987
1010
|
logger.debug(context, 'Updating device value in the Context Broker at [%s]', options.url);
|
|
@@ -62,7 +62,6 @@ const provisioningAPITranslation = {
|
|
|
62
62
|
static_attributes: 'staticAttributes',
|
|
63
63
|
autoprovision: 'autoprovision',
|
|
64
64
|
explicitAttrs: 'explicitAttrs',
|
|
65
|
-
expressionLanguage: 'expressionLanguage',
|
|
66
65
|
ngsiVersion: 'ngsiVersion',
|
|
67
66
|
entityNameExp: 'entityNameExp'
|
|
68
67
|
};
|
|
@@ -142,7 +141,6 @@ function handleProvision(req, res, next) {
|
|
|
142
141
|
internalId: null,
|
|
143
142
|
autoprovision: body.autoprovision,
|
|
144
143
|
explicitAttrs: body.explicitAttrs,
|
|
145
|
-
expressionLanguage: body.expressionLanguage,
|
|
146
144
|
ngsiVersion: body.ngsiVersion
|
|
147
145
|
});
|
|
148
146
|
}
|
|
@@ -219,7 +217,6 @@ function toProvisioningAPIFormat(device) {
|
|
|
219
217
|
internal_attributes: device.internalAttributes,
|
|
220
218
|
protocol: device.protocol,
|
|
221
219
|
autoprovision: device.autoprovision,
|
|
222
|
-
expressionLanguage: device.expressionLanguage,
|
|
223
220
|
explicitAttrs: device.explicitAttrs,
|
|
224
221
|
ngsiVersion: device.ngsiVersion
|
|
225
222
|
};
|
|
@@ -36,10 +36,6 @@
|
|
|
36
36
|
"description": "Transport protocol used by the platform to communicate with the device",
|
|
37
37
|
"type": "string"
|
|
38
38
|
},
|
|
39
|
-
"expressionLanguage": {
|
|
40
|
-
"description": "Expression language used to apply expressions for this device",
|
|
41
|
-
"type": "string"
|
|
42
|
-
},
|
|
43
39
|
"explicitAttrs": {
|
|
44
40
|
"description": "Flag about only provisioned attributes will be processed to Context Broker"
|
|
45
41
|
},
|
|
@@ -36,10 +36,6 @@
|
|
|
36
36
|
"description": "Transport protocol used by the platform to communicate with the device",
|
|
37
37
|
"type": "string"
|
|
38
38
|
},
|
|
39
|
-
"expressionLanguage": {
|
|
40
|
-
"description": "Expression language used to apply expressions for this device",
|
|
41
|
-
"type": "string"
|
|
42
|
-
},
|
|
43
39
|
"explicitAttrs": {
|
|
44
40
|
"description": "Flag about only provisioned attributes will be processed to Context Broker"
|
|
45
41
|
},
|