Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
d79cb49
use targetEntityId and targetEntityType from subscription
AlvaroVega Jan 25, 2024
b29e4c6
fix access to targetEntityId and targetEntityType
AlvaroVega Jan 25, 2024
28bde7c
export executeUpdateSideEffects
AlvaroVega Jan 29, 2024
9ec6e26
Merge branch 'master' into task/notify_cmd
AlvaroVega Jan 30, 2024
ce01e87
fix export executeUpdateSideEffects
AlvaroVega Jan 30, 2024
5014749
Merge branch 'master' into task/notify_cmd
AlvaroVega Jan 30, 2024
50dcd61
add missed exports.executeUpdateSideEffects
AlvaroVega Jan 30, 2024
bbbe334
update CNR
AlvaroVega Jan 30, 2024
48cf466
Merge branch 'master' into task/notify_cmd
AlvaroVega Jan 30, 2024
010931f
explain how CB notifies a command to iotagent
AlvaroVega Jan 31, 2024
1058a05
add new fields to command
AlvaroVega Jan 31, 2024
b92f5b6
add new command fields
AlvaroVega Jan 31, 2024
ad89896
fix json
AlvaroVega Feb 5, 2024
b07c2ef
update CNR
AlvaroVega Feb 5, 2024
0ecb5aa
Merge branch 'master' into task/notify_cmd
fgalan Feb 5, 2024
d6bb406
Merge branch 'master' into task/notify_cmd
AlvaroVega Feb 21, 2024
cc3d345
Merge branch 'master' into task/notify_cmd
AlvaroVega Feb 28, 2024
ae08bd6
Merge branch 'master' into task/notify_cmd
AlvaroVega Apr 17, 2024
5b11591
Merge branch 'master' into task/notify_cmd
AlvaroVega Jun 20, 2024
186ef0a
Merge branch 'master' into task/notify_cmd
AlvaroVega Aug 19, 2024
a690249
Merge branch 'master' into task/notify_cmd
AlvaroVega Aug 30, 2024
902402d
Merge branch 'master' into task/notify_cmd
AlvaroVega Sep 16, 2024
645c932
Merge branch 'master' into task/notify_cmd
AlvaroVega Jan 22, 2025
b67ef34
Merge branch 'master' into task/notify_cmd
AlvaroVega Feb 24, 2025
7f30570
Merge branch 'master' into task/notify_cmd
AlvaroVega Apr 1, 2025
7a5980c
Merge branch 'master' into task/notify_cmd
AlvaroVega Apr 22, 2025
850ba02
update notify command about new fields·
AlvaroVega Apr 23, 2025
1c9302d
check targetEntityId.value and targetEntityType.value before use it
AlvaroVega Apr 23, 2025
3b7b43f
simplify usage of targetEntityId and targetEntityType if provided
AlvaroVega Apr 23, 2025
4c034f1
update doc
AlvaroVega Apr 30, 2025
51b7d66
Merge branch 'master' into task/notify_cmd
AlvaroVega May 20, 2025
52e8700
Update northboundinteractions.md
fgalan May 22, 2025
f03a6e1
Update contextServer-NGSI-v2.js
AlvaroVega May 22, 2025
b04cc1c
Update contextServer-NGSI-v2.js
AlvaroVega May 22, 2025
b841699
Update contextServer-NGSI-v2.js
AlvaroVega May 22, 2025
f578570
Update contextServer-NGSI-v2.js
AlvaroVega May 22, 2025
ba7fe16
Update contextServer-NGSI-v2.js
AlvaroVega May 22, 2025
4a59474
Merge branch 'master' into task/notify_cmd
fgalan May 22, 2025
bdd601a
FIX commands model doc adding new fields
fgalan May 22, 2025
0391a14
FIX syntax
fgalan May 22, 2025
c07c3c4
remove support for subscriptions for bidirectional plugin
AlvaroVega May 22, 2025
fb0642f
Update CHANGES_NEXT_RELEASE
fgalan May 22, 2025
b804cbb
FIX doc northboundinteractions.md
fgalan May 22, 2025
c162fce
Update doc/devel/northboundinteractions.md
fgalan May 22, 2025
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
3 changes: 2 additions & 1 deletion CHANGES_NEXT_RELEASE
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
- Add: notification-based commands (#1455)
- Add: allow define headers in device commands (iotagent-json#873)
- Add: index for Device model based on {service: 1, subservice: 1, id: 1, apikey: 1} (#1576)
- Fix: Duplicated Devices when burst measures to non provisioned Device (iotagent-json#865)
- Fix: modified JEXL transformations (toisostring, gettime, parseint, etc.) to return null instead of NaN when some unexpected situation occurs (#1701)
- Fix: modified JEXL transformations (toisostring, gettime, parseint, etc.) to return null instead of NaN when some unexpected situation occurs (#1701)
132 changes: 117 additions & 15 deletions doc/devel/northboundinteractions.md
Original file line number Diff line number Diff line change
Expand Up @@ -775,6 +775,8 @@ The registration of the commands is performed once in the lifetime of the Device

#### Command Execution

##### Based in update (classic way)

Scenario 3 begins with the request for a command from the User to the Context Broker (P1):

```bash
Expand Down Expand Up @@ -825,21 +827,7 @@ Fiware-Correlator: 9cae9496-8ec7-11e6-80fc-fa163e734aab
}
```

The IoT Agent detects the selected attribute is a command, and replies to the Context Broker with the following payload
(200 OK):

```json
[
{
"type": "device",
"id": "Dev0001",
"switch": {
"type": "command",
"value": ""
}
}
]
```
The IoT Agent detects the selected attribute is a command, and replies to the Context Broker with a 204 OK (without payload).
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems documentation was not aligned with the code in this case.


This response just indicates that the IoT Agent has received the command successfully, and gives no information about
the requested information or command execution.
Expand All @@ -862,6 +850,99 @@ The Context Broker, forwards the same response to the user, thus replying the or
At this point, the command has been issued to the IoTAgent and the User doesn't still know what the result of its
request will be.

##### Based in notification (new way)

A new way to ContextBroker provides a command to a IoTAgent is through notifications. In this case CB notify the command
to the IotAgent with a request like the following:

```bash
POST /notify HTTP/1.1
Host: <target-host>:<northbound_port>
fiware-service: workshop
Fiware-ServicePath: /iota2ngsi
Accept: application/json
Content-length: 290
Content-type: application/json; charset=utf-8
Fiware-Correlator: 9cae9496-8ec7-11e6-80fc-fa163e734aab

{
"subscriptionId": "60b0cedd497e8b681d40b58e",
"data": [{
"id": "123456abcdefg",
"type": "switchOnOffExecution",
"targetEntityId": {
"type": "Text",
"value": "Dev0001",
"metadata": {}
},
"targetEntityType": {
"type": "Text",
"value": "device",
"metadata": {}
},
"execTs": {
"type": "DateTime",
"value": "2020-05-27T00:00:00.000Z",
"metadata": {}
},
"cmd": {
"type": "Text",
"value": "switch",
"metadata": {}
},
"params": {
"type": "Text",
"value": "54, 12",
"metadata": {}
},
"status": {
"type": "Text",
"value": "FORWARDED",
"metadata": {}
},
"info": {
"type": "Text",
"value": null,
"metadata": {}
},
"onDelivered": {
"type": "Request",
"value": {
}
},
"onOk": {
"type": "Request",
"value": {
}
},
"onError": {
"type": "Request",
"value": {
}
},
"onInfo": {
"type": "Request",
"value": {
}
},
"cmdExecution": {
"type": "value",
"value": true,
"metadata": {}
},
"dateExpiration": {
"type": "DateTime",
"value": "2020-05-27T20:00:00.000Z",
"metadata": {}
}
}]
}
```

In this case relevant fields are just `targetEntityId`, `targetEntityType`, `cmd` and `params`.

The IoT Agent detects the selected attribute is a command, and replies to the Context Broker with a 204 OK (without payload).

#### Result reporting

Once the IoT Agent has executed the command or retrieved the information from the device, it reports the results to the
Expand Down Expand Up @@ -955,6 +1036,27 @@ The Context Broker replies with all the desired data, in R2 format (200 OK):
]
```

#### Differences regarding the new commands mode

A new commands flow has been defined (involving also modifications at ContextBroker). As part of that design, commands
are not sent to IOTAs using NGSIv2 notifications, but the current implementation has some differences regarding the
desired behaviour, which are described next:

* Fields others than `targetEntityId`, `targetEntityType`, `cmd` and `params` (i.e. `execTs`,
`status`, `info`, `onDelivered`, `onOk`, `onError`, `onInfo`, `cmdExecution` and `dataExpiration`), are not actually used. By
the moment they are stored in the commands model (commands collection) but nothing is done with them appart from storing.
* The "Result reporting" should not be a "hardwired" behaviour updating the entity associated to the device,
but using the corresponding `on*` attribute in the notificaiton (e.g. `onOk` in the case of success). That attribute would typically
be a [HATEOAS](https://en.wikipedia.org/wiki/HATEOAS) object like this `"onOk": { "href": "/v2/entities/123456abcdefg/attrs/status?type=switchExecution", "method": "PUT" }`. Moreover, the
entity to be updated in that HATEOAS would be the transient entity corresponding to command execuion, not the entity associated to the device.

```
PUT /v2/entities/123456abcdefg/attrs/status?type=switchExecution
content-type: text/plain

OK
```

### Scenario 3: commands (error)

In Scenario 3, errors can happen asynchronously, out of the main interactions. When the IoTAgent detects an error
Expand Down
9 changes: 9 additions & 0 deletions doc/models/models.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,15 @@ Fields:
- **value** _object_: value of the command
- **service** _string_: service which the device command belongs to
- **subservice** _string_: subservice which the device command belongs to
- **execTs** _date_: related with new commands functionality (stored but not yet in use)
- **status** _string_: related with new commands functionality (stored but not yet in use)
- **info** _string_: related with new commands functionality (stored but not yet in use)
- **onDelivered** _Object_: related with new commands functionality (stored but not yet in use)
- **onOk**: _Object_: related with new commands functionality (stored but not yet in use)
- **onError** _Object_: related with new commands functionality (stored but not yet in use)
- **onInfo** _Object_: related with new commands functionality (stored but not yet in use)
- **cmdExecution** _Boolean__: related with new commands functionality (stored but not yet in use)
- **dateExpiration**: { type: Date }: related with new commands functionality (stored but not yet in use)
- **creationDate** _date_: creation date of command

Example:
Expand Down
1 change: 1 addition & 0 deletions lib/fiware-iotagent-lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ exports.setDataUpdateHandler = contextServer.setUpdateHandler;
exports.setCommandHandler = contextServer.setCommandHandler;
exports.setMergePatchHandler = contextServer.setMergePatchHandler;
exports.setDataQueryHandler = contextServer.setQueryHandler;
exports.executeUpdateSideEffects = contextServer.executeUpdateSideEffects;
exports.setConfigurationHandler = contextServer.setConfigurationHandler;
exports.setRemoveConfigurationHandler = contextServer.setRemoveConfigurationHandler;
exports.setProvisioningHandler = contextServer.setProvisioningHandler;
Expand Down
9 changes: 9 additions & 0 deletions lib/model/Command.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ const Command = new Schema({
value: Object,
service: { type: String, lowercase: true },
subservice: String,
execTs: { type: Date },
status: String,
info: String,
onDelivered: Object,
onOk: Object,
onError: Object,
onInfo: Object,
cmdExecution: Boolean,
dateExpiration: { type: Date },
creationDate: { type: Date, default: Date.now }
});

Expand Down
16 changes: 15 additions & 1 deletion lib/services/commands/commandRegistryMongoDB.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,21 @@ function updateCommand(service, subservice, deviceId, command, callback) {
function createCommand(service, subservice, deviceId, command, callback) {
/* eslint-disable-next-line new-cap */
const commandObj = new Command.model();
const attributeList = ['name', 'type', 'value'];
const attributeList = [
'name',
'type',
'value',
// new Command fields
'execTs',
'status',
'info',
'onDelivered',
'onOk',
'onError',
'onInfo',
'cmdExecution',
'dateExpiration'
Comment thread
AlvaroVega marked this conversation as resolved.
];

for (let i = 0; i < attributeList.length; i++) {
commandObj[attributeList[i]] = command[attributeList[i]];
Expand Down
6 changes: 3 additions & 3 deletions lib/services/commands/commandService.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ function listCommands(service, subservice, deviceId, callback) {
}

function addCommand(service, subservice, deviceId, command, callback) {
logger.debug(context, 'Adding command [%j] to the queue for device [%s]', command, deviceId);
logger.debug(context, 'Adding command [%j] to the queue for deviceId [%s]', command, deviceId);
config.getCommandRegistry().add(service, subservice, deviceId, command, callback);
}

Expand Down Expand Up @@ -73,13 +73,13 @@ function addCommandDevice(service, subservice, device, command, callback) {
}

function updateCommand(service, subservice, deviceId, name, value, callback) {
logger.debug(context, 'Updating command [%s] for device [%s] with value [%s]', name, deviceId, value);
logger.debug(context, 'Updating command [%s] for deviceId [%s] with value [%s]', name, deviceId, value);

config.getCommandRegistry().update(service, subservice, deviceId, value, callback);
}

function removeCommand(service, subservice, deviceId, name, callback) {
logger.debug(context, 'Removing command [%s] from device [%s]', name, deviceId);
logger.debug(context, 'Removing command [%s] from deviceId [%s]', name, deviceId);

config.getCommandRegistry().remove(service, subservice, deviceId, name, callback);
}
Expand Down
15 changes: 12 additions & 3 deletions lib/services/northBound/contextServer-NGSI-v2.js
Original file line number Diff line number Diff line change
Expand Up @@ -292,9 +292,18 @@ function handleNotificationNgsi2(req, res, next) {
}
}
}
logger.debug(context, 'extracted atts %j from dataElement %j', atts, dataElement);
var id = null;
var type = null;
if (dataElement.targetEntityId && dataElement.targetEntityId.value) {
id = dataElement.targetEntityId.value;
}
if (dataElement.targetEntityType && dataElement.targetEntityType.value) {
type = dataElement.targetEntityType.value;
}
deviceService.getDeviceByNameAndType(
dataElement.id,
dataElement.type,
id,
type,
req.headers['fiware-service'],
req.headers['fiware-servicepath'],
function (error, device) {
Expand Down Expand Up @@ -336,7 +345,7 @@ function handleNotificationNgsi2(req, res, next) {
logger.error(context, 'Error found when processing notification: %j', error);
next(error);
} else {
res.status(200).json({});
res.status(204).json();
}
}

Expand Down
3 changes: 2 additions & 1 deletion lib/services/northBound/contextServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const context = {
op: 'IoTAgentNGSI.ContextServer'
};
const contextServerUtils = require('./contextServerUtils');

const executeUpdateSideEffects = contextServerUtils.executeUpdateSideEffects;
let contextServerHandler;

/**
Expand Down Expand Up @@ -157,4 +157,5 @@ exports.setCommandHandler = intoTrans(context, setCommandHandler);
exports.setNotificationHandler = intoTrans(context, setNotificationHandler);
exports.addNotificationMiddleware = intoTrans(context, addNotificationMiddleware);
exports.setQueryHandler = intoTrans(context, setQueryHandler);
exports.executeUpdateSideEffects = intoTrans(context, executeUpdateSideEffects);
exports.init = init;
1 change: 1 addition & 0 deletions lib/services/northBound/northboundServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ exports.setRemoveDeviceHandler = intoTrans(context, deviceProvisioning.setRemove
exports.addDeviceProvisionMiddleware = deviceProvisioning.addDeviceProvisionMiddleware;
exports.addConfigurationProvisionMiddleware = groupProvisioning.addConfigurationProvisionMiddleware;
exports.addNotificationMiddleware = contextServer.addNotificationMiddleware;
exports.executeUpdateSideEffects = contextServer.executeUpdateSideEffects;
exports.clear = clear;
exports.start = intoTrans(context, start);
exports.stop = intoTrans(context, stop);
Expand Down
Loading