Skip to content

Commit

Permalink
Merge branch 'master' into patch-1
Browse files Browse the repository at this point in the history
chandradeep11 authored Oct 29, 2020
2 parents 255317a + c4a81d2 commit cf23111
Showing 3 changed files with 79 additions and 8 deletions.
1 change: 1 addition & 0 deletions CHANGES_NEXT_RELEASE
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
Add: use mqtt.qos and mqtt.retain values from command for command execution (#504)
Add: log in info level command and configuration MQTT
FIX: check ngsi version in configuration handler (#500)
Add missed global config env vars (IOTA_CONFIG_RETRIEVAL, IOTA_DEFAULT_KEY, IOTA_DEFAULT_TRANSPORT)
49 changes: 49 additions & 0 deletions docs/usermanual.md
Original file line number Diff line number Diff line change
@@ -85,6 +85,55 @@ following query parameters:
- **k (API Key)**: API Key for the service the device is registered on.
- **t (timestamp)**: Timestamp of the measure. Will override the automatic IoTAgent timestamp (optional).


=======
#### Sending Commands

MQTT devices commands are always push. For HTTP Devices commands to be push they **must** be provisioned with the
`endpoint` attribute, that will contain the URL where the IoT Agent will send the received commands. Otherwise the
command will be poll. When using the HTTP transport, the command handling have two flavours:

- **Push commands**: The request payload format will be a plain JSON, as described in the "Payload" section. The
device will reply with a 200OK response containing the result of the command in the JSON result format.

- **Polling commands**: in this case, the Agent does not send any messages to the device, being the later responsible
of retrieving them from the IoTAgent whenever the device is ready to get commands. In order to retrieve commands
from the IoT Agent, the device will send the query parameter 'getCmd' with value '1' as part of a normal measure. As
a result of this action, the IoTAgent, instead of returning an empty body (the typical response to a measurement
report), will return a list of all the commands available for the device, in JSON format: each attribute will
represent a command, and its value the command value. The use of a JSON return object implies that only one value
can be returned for each command (last value will be returned for each one). Implementation imposes another
limitation in the available values for the commands: a command value can't be an empty string, or a string composed
exclusively by whitespaces. Whenever the device has completed the execution of the command, it will send the
response in the same way measurements are reported, but using the **command result format** as exposed in the
[Protocol section](#protocol).

Some additional remarks regarding polling commands:

- Commands can be also retrieved without needed of sending a mesaure. In other words, the device is not forced to send
a measure in order to get the accumulated commands. However, in this case note that `GET` method is used to carry
the `getCmd=1` query parameter (as they are no actual payload for measures, `POST` wouldn't make too much sense).
- MQTT devices can configure (at provisioning and updating time) each command with different values of MQTT QoS and MQTT retain values, which will be used only by a command. Moreover, in the same MQTT device different commands can be configured to use different MQTT options related with QoS level and Retain message policy. I.E:

```json
{

"commands": [
{
"type": "command",
"name": "a_command_name_A",
"mqtt": { "qos": 2, "retain": true }
},
{
"type": "command",
"name": "a_command_name_B",
"mqtt": { "qos": 1, "retain": false }
}
]

}
```

#### Configuration retrieval

The protocol offers a mechanism for the devices to retrieve its configuration (or any other value it needs from those
37 changes: 29 additions & 8 deletions lib/bindings/MQTTBinding.js
Original file line number Diff line number Diff line change
@@ -329,16 +329,37 @@ function stop(callback) {
*/
function executeCommand(apiKey, device, serializedPayload, callback) {
const options = {};
if (config.getConfig().mqtt.qos) {
options.qos = parseInt(config.getConfig().mqtt.qos) || 0;
}
if (config.getConfig().mqtt.retain === true) {
options.retain = config.getConfig().mqtt.retain;
}
config.getLogger().debug(context, 'Sending cmd to the device:\n %j', serializedPayload);
// retrieve command mqtt options from device
var cmdName = Object.keys(JSON.parse(serializedPayload))[0];
var commands = Object.assign({}, ...device.commands.map((c) => ({[c.name]: c})));

options.qos =
commands[cmdName].mqtt && commands[cmdName].mqtt.qos
? commands[cmdName].mqtt.qos
: config.getConfig().mqtt.qos
? parseInt(config.getConfig().mqtt.qos)
: 0;
options.retain =
commands[cmdName].mqtt && commands[cmdName].mqtt.retain
? commands[cmdName].mqtt.retain
: config.getConfig().mqtt.retain
? config.getConfig().mqtt.retain
: false;

const commandTopic = '/' + apiKey + '/' + device.id + '/cmd';
config.getLogger().debug(
context,
'Sending command execution to [%s] with payload [%s] and with mqtt options [%j]',
commandTopic,
serializedPayload,
options);
mqttClient.publish(commandTopic, serializedPayload, options);
config.getLogger().info(context, 'Cmd:\n %j was sent to the device %s', serializedPayload, commandTopic);
config.getLogger().info(
context,
'Cmd:\n %j was sent to the device %s with mqtt options %j',
serializedPayload,
commandTopic,
options);
callback();
}

0 comments on commit cf23111

Please sign in to comment.