Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

send to CB using multimeasures #677

Merged
merged 9 commits into from
May 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES_NEXT_RELEASE
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
- Fix: allow send multiple measures to CB in a batch (POST /v2/op/update) and sorted by TimeInstant when possible, instead of using multiples single request (iotagent-json#825, iotagent-node-lib#1612)
- Fix: default express limit to 1Mb instead default 100Kb and allow change it throught a conf env var 'IOTA_EXPRESS_LIMIT' (iota-json#827)
5 changes: 2 additions & 3 deletions docs/usermanual.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,14 @@ t|15|k|abc
In this example, two attributes, one named "t" with value "15" and another named "k" with value "abc" are transmitted.
Values in Ultralight 2.0 are not typed (everything is treated as a string).

Multiple groups of measures can be combined into a single request, using the `#` character. In that case, a different
Multiple groups of measures can be combined into a single request (but just for HTTP/POST or MQTT), using the `#` character. In that case, a different
NGSI request will be generated for each group of measures. E.g.:

```text
gps|1.2/3.4#t|10
```

This will generate two NGSI requests for the same entity, one for each one of the values. Each one of those requests can
contain any number of attributes.
This will generate two elements in the NGSI batch update request (POST /v2/op/update) for the same entity, one for each one of the measures. Each one of those elements can contain any number of attributes.

Measure groups can additionally have an optional timestamp, with the following syntax:

Expand Down
6 changes: 3 additions & 3 deletions lib/bindings/HTTPBindings.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ function returnCommands(req, res, next) {
}

function handleIncomingMeasure(req, res, next) {
let updates = [];
let update = [];
context = fillService(context, { service: 'n/a', subservice: 'n/a' });
// prettier-ignore
config.getLogger().debug(context, 'Processing multiple HTTP measures for device %s with apiKey %j',
Expand All @@ -223,10 +223,10 @@ function handleIncomingMeasure(req, res, next) {
function processHTTPWithDevice(device) {
context = fillService(context, device);
if (req.ulPayload) {
updates = req.ulPayload.reduce(commonBindings.processMeasureGroup.bind(null, device, req.apiKey), []);
update = [req.ulPayload].reduce(commonBindings.processMeasureGroup.bind(null, device, req.apiKey), []);
}

async.series(updates, function (error) {
async.series(update, function (error) {
if (error) {
next(error);
// prettier-ignore
Expand Down
35 changes: 19 additions & 16 deletions lib/commonBindings.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,32 +128,35 @@ function manageConfigurationRequest(apiKey, deviceId, device, objMessage) {

/* eslint-disable-next-line no-unused-vars */
function processMeasureGroup(device, apikey, previous, current, index) {
const values = [];
if (current.command) {
if (current[0] && current[0].command) {
previous.push(
iotAgentLib.setCommandResult.bind(
null,
device.name,
config.getConfig().iota.defaultResource,
apikey,
current.command,
current.value,
current[0].command,
current[0].value,
constants.COMMAND_STATUS_COMPLETED,
device
)
);
} else {
for (const k in current) {
if (current.hasOwnProperty(k)) {
values.push({
name: k,
type: guessType(k, device),
value: current[k]
});
const val = [];
for (let curr of current) {
const values = [];
for (const k in curr) {
if (curr.hasOwnProperty(k)) {
values.push({
name: k,
type: guessType(k, device),
value: curr[k]
});
}
}
val.push(values);
}

previous.push(iotAgentLib.update.bind(null, device.name, device.type, '', values, device));
previous.push(iotAgentLib.update.bind(null, device.name, device.type, '', val, device));
}

return previous;
Expand All @@ -168,7 +171,7 @@ function processMeasureGroup(device, apikey, previous, current, index) {
* @param {String} messageStr UL payload parsed to string.
*/
function multipleMeasures(apiKey, device, messageStr) {
let updates = [];
let update = [];
let parsedMessage;
context = fillService(context, device);
config.getLogger().debug(context, 'Processing multiple measures for device %s with apiKey %s', device.id, apiKey);
Expand All @@ -181,9 +184,9 @@ function multipleMeasures(apiKey, device, messageStr) {
return;
}
config.getLogger().debug(context, 'stringMessage: %s parsedMessage: %s', messageStr, parsedMessage);
updates = parsedMessage.reduce(processMeasureGroup.bind(null, device, apiKey), []);
update = [parsedMessage].reduce(processMeasureGroup.bind(null, device, apiKey), []);

async.series(updates, function (error) {
async.series(update, function (error) {
if (error) {
config.getLogger().error(
context,
Expand Down
28 changes: 2 additions & 26 deletions test/unit/ngsiv2/amqpBinding-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -218,19 +218,7 @@ describe('AMQP Transport binding: measures', function () {
contextBrokerMock
.matchHeader('fiware-service', 'smartgondor')
.matchHeader('fiware-servicepath', '/gardens')
.post(
'/v2/entities?options=upsert',
utils.readExampleFile('./test/unit/ngsiv2/contextRequests/singleMeasure.json')
)
.reply(204);

contextBrokerMock
.matchHeader('fiware-service', 'smartgondor')
.matchHeader('fiware-servicepath', '/gardens')
.post(
'/v2/entities?options=upsert',
utils.readExampleFile('./test/unit/ngsiv2/contextRequests/secondSingleMeasure.json')
)
.post('/v2/op/update', utils.readExampleFile('./test/unit/ngsiv2/contextRequests/multimeasure.json'))
.reply(204);
});

Expand All @@ -248,19 +236,7 @@ describe('AMQP Transport binding: measures', function () {
contextBrokerMock
.matchHeader('fiware-service', 'smartgondor')
.matchHeader('fiware-servicepath', '/gardens')
.post(
'/v2/entities?options=upsert',
utils.readExampleFile('./test/unit/ngsiv2/contextRequests/multipleMeasure.json')
)
.reply(204);

contextBrokerMock
.matchHeader('fiware-service', 'smartgondor')
.matchHeader('fiware-servicepath', '/gardens')
.post(
'/v2/entities?options=upsert',
utils.readExampleFile('./test/unit/ngsiv2/contextRequests/secondMultipleMeasure.json')
)
.post('/v2/op/update', utils.readExampleFile('./test/unit/ngsiv2/contextRequests/multimeasure2.json'))
.reply(204);
});

Expand Down
21 changes: 21 additions & 0 deletions test/unit/ngsiv2/contextRequests/multimeasure.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"actionType": "append",
"entities": [
{
"id": "Second UL Device",
"type": "AnMQTTDevice",
"temperature": {
"type": "celsius",
"value": 23
}
},
{
"id": "Second UL Device",
"type": "AnMQTTDevice",
"humidity": {
"type": "degrees",
"value": 98
}
}
]
}
29 changes: 29 additions & 0 deletions test/unit/ngsiv2/contextRequests/multimeasure2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"actionType": "append",
"entities": [
{
"id": "Second UL Device",
"type": "AnMQTTDevice",
"temperature": {
"type": "celsius",
"value": 23
},
"humidity": {
"type": "degrees",
"value": 98
}
},
{
"id": "Second UL Device",
"type": "AnMQTTDevice",
"temperature": {
"type": "celsius",
"value": 16
},
"humidity": {
"type": "degrees",
"value": 34
}
}
]
}
Loading
Loading