diff --git a/CHANGES_NEXT_RELEASE b/CHANGES_NEXT_RELEASE index bc8222f6c..c66701ce1 100644 --- a/CHANGES_NEXT_RELEASE +++ b/CHANGES_NEXT_RELEASE @@ -7,3 +7,4 @@ - Add: attribute metadata and static attributes metadata added to jexl context (#1630) - Add /iot/groups API endpoints (as equivalent to /iot/services) (#752) - Deprecated: /iot/services API routes +- Add: extend handleNotificationNgsi2 to allow receive commands from CB notifications (#1455) \ No newline at end of file diff --git a/doc/devel/northboundinteractions.md b/doc/devel/northboundinteractions.md index 0554dbae4..783b3ab50 100644 --- a/doc/devel/northboundinteractions.md +++ b/doc/devel/northboundinteractions.md @@ -825,8 +825,95 @@ 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): +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: : +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 both cases (update or command) the IoT Agent detects the selected attribute is a command, and replies to the Context +Broker with the following payload (200 OK): ```json [ diff --git a/lib/fiware-iotagent-lib.js b/lib/fiware-iotagent-lib.js index 1c057e819..52d863505 100644 --- a/lib/fiware-iotagent-lib.js +++ b/lib/fiware-iotagent-lib.js @@ -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; diff --git a/lib/model/Command.js b/lib/model/Command.js index 5205ea0f0..6331c8649 100644 --- a/lib/model/Command.js +++ b/lib/model/Command.js @@ -31,6 +31,15 @@ const Command = new Schema({ value: Object, service: { type: String, lowercase: true }, subservice: String, + execTs: { type: Date }, + status: Object, + info: Object, + onDelivered: Object, + onOk: Object, + onError: Object, + onInfo: Object, + cmdExecution: Object, + dateExpiration: { type: Date }, creationDate: { type: Date, default: Date.now } }); diff --git a/lib/services/commands/commandRegistryMongoDB.js b/lib/services/commands/commandRegistryMongoDB.js index a3df434ca..6a7192687 100644 --- a/lib/services/commands/commandRegistryMongoDB.js +++ b/lib/services/commands/commandRegistryMongoDB.js @@ -82,7 +82,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' + ]; for (let i = 0; i < attributeList.length; i++) { commandObj[attributeList[i]] = command[attributeList[i]]; diff --git a/lib/services/commands/commandService.js b/lib/services/commands/commandService.js index 757e4d2ba..af766a6a0 100644 --- a/lib/services/commands/commandService.js +++ b/lib/services/commands/commandService.js @@ -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); } @@ -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); } diff --git a/lib/services/northBound/contextServer-NGSI-v2.js b/lib/services/northBound/contextServer-NGSI-v2.js index d7bbf8711..9f3db67fb 100644 --- a/lib/services/northBound/contextServer-NGSI-v2.js +++ b/lib/services/northBound/contextServer-NGSI-v2.js @@ -292,19 +292,36 @@ function handleNotificationNgsi2(req, res, next) { } } } - deviceService.getDeviceByNameAndType( - dataElement.id, - dataElement.type, - req.headers['fiware-service'], - req.headers['fiware-servicepath'], - function (error, device) { - if (error) { - callback(error); - } else { - callback(null, device, atts); + logger.debug(context, 'extracted atts %j from dataElement %j', atts, dataElement); + if (dataElement.targetEntityId && dataElement.targetEntityType) { + deviceService.getDeviceByNameAndType( + dataElement.targetEntityId.value, + dataElement.targetEntityType.value, + req.headers['fiware-service'], + req.headers['fiware-servicepath'], + function (error, device) { + if (error) { + callback(error); + } else { + callback(null, device, atts); + } } - } - ); + ); + } else { + deviceService.getDeviceByNameAndType( + dataElement.id, + dataElement.type, + req.headers['fiware-service'], + req.headers['fiware-servicepath'], + function (error, device) { + if (error) { + callback(error); + } else { + callback(null, device, atts); + } + } + ); + } } function applyNotificationMiddlewares(device, values, callback) { diff --git a/lib/services/northBound/contextServer.js b/lib/services/northBound/contextServer.js index f328e6730..f901de3df 100644 --- a/lib/services/northBound/contextServer.js +++ b/lib/services/northBound/contextServer.js @@ -30,7 +30,7 @@ const context = { op: 'IoTAgentNGSI.ContextServer' }; const contextServerUtils = require('./contextServerUtils'); - +const executeUpdateSideEffects = contextServerUtils.executeUpdateSideEffects; let contextServerHandler; /** @@ -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; diff --git a/lib/services/northBound/northboundServer.js b/lib/services/northBound/northboundServer.js index c5f2d8b7d..5f7b96579 100644 --- a/lib/services/northBound/northboundServer.js +++ b/lib/services/northBound/northboundServer.js @@ -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);