Skip to content

Commit

Permalink
update doc
Browse files Browse the repository at this point in the history
  • Loading branch information
AlvaroVega committed Dec 20, 2023
1 parent 214e8b2 commit 26dd0bc
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 144 deletions.
3 changes: 1 addition & 2 deletions CHANGES_NEXT_RELEASE
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@


- ADD: check and usage endpoint and transport from Group level when commands
111 changes: 54 additions & 57 deletions docs/usermanual.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,60 +149,59 @@ then the NGSI v2 update uses `10`(number), `true` (boolean) and `78.8` (number)
(string) and "78.8" (string).

This functionality relies on string measures casting feature implemented in the iotagent library. This functionality
uses native JavaScript [`JSON.parse()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse)
function to cast data coming from measures (as text) to JSON native types. This functionality does not change the attribute type,
using the type specified in the config group or device provision, even if it is not consistent with the measures that are coming.

uses native JavaScript
[`JSON.parse()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse) function
to cast data coming from measures (as text) to JSON native types. This functionality does not change the attribute type,
using the type specified in the config group or device provision, even if it is not consistent with the measures that
are coming.
As an example, for a given measure:

```
a|1|b|1.01|c|true|d|null|e|[1,2,3]|f|['a','b','c']|g|{a:1,b:2,c:3}|h|I'm a string
a|1|b|1.01|c|true|d|null|e|[1,2,3]|f|['a','b','c']|g|{a:1,b:2,c:3}|h|I'm a string
```

The resulting entity would be something like:

```json
{
"id": "entityid:001",
"type": "entitytype",
"a": {
"type": "provisionedType",
"value": 1
},
"b": {
"type": "provisionedType",
"value": 1.01
},
"c": {
"type": "provisionedType",
"value": true
},
"d": {
"type": "provisionedType",
"value": null
},
"e": {
"type": "provisionedType",
"value": [1,2,3]
},
"f": {
"type": "provisionedType",
"value": ["a","b","c"]
},
"g": {
"type": "provisionedType",
"value": {"a":1,"b":2,"c":3}
},
"h": {
"type": "provisionedType",
"value": "I'm a string"
}
"id": "entityid:001",
"type": "entitytype",
"a": {
"type": "provisionedType",
"value": 1
},
"b": {
"type": "provisionedType",
"value": 1.01
},
"c": {
"type": "provisionedType",
"value": true
},
"d": {
"type": "provisionedType",
"value": null
},
"e": {
"type": "provisionedType",
"value": [1, 2, 3]
},
"f": {
"type": "provisionedType",
"value": ["a", "b", "c"]
},
"g": {
"type": "provisionedType",
"value": { "a": 1, "b": 2, "c": 3 }
},
"h": {
"type": "provisionedType",
"value": "I'm a string"
}
}
```

Note that `provisionedType` is the type included in the device provision or config group, and it is not changed.


Note that `provisionedType` is the type included in the device provision or config group, and it is not changed.

### Transport Protocol

Expand Down Expand Up @@ -247,8 +246,8 @@ and
[Practice: Scenario 3: commands - error](https://github.com/telefonicaid/iotagent-node-lib/blob/master/doc/northboundinteractions.md#scenario-3-commands-error).

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:
`endpoint` attribute, from device or group device, 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 the one described in the UL Protocol description. The device
will reply with a 200OK response containing the result of the command in the UL2.0 result format. Example of the
Expand Down Expand Up @@ -315,19 +314,16 @@ by the protocol, in this case '/ul', just include apikey and deviceid (e.g: `/FF

> **Note** Measures and commands are sent over different MQTT topics:
>
> * _Measures_ are sent on the `/<protocol>/<api-key>/<device-id>/attrs` topic,
> * _Commands_ are sent on the `/<api-key>/<device-id>/cmd` topic,
> - _Measures_ are sent on the `/<protocol>/<api-key>/<device-id>/attrs` topic,
> - _Commands_ are sent on the `/<api-key>/<device-id>/cmd` topic,
>
> The reasoning behind this is that when sending measures northbound from device to IoT Agent,
> it is necessary to explicitly identify which IoT Agent is needed to parse the data. This
> is done by prefixing the relevant MQTT topic with a protocol, otherwise there is no way to
> define which agent is processing the measure. This mechanism allows smart systems to connect
> different devices to different IoT Agents according to need.
> The reasoning behind this is that when sending measures northbound from device to IoT Agent, it is necessary to
> explicitly identify which IoT Agent is needed to parse the data. This is done by prefixing the relevant MQTT topic
> with a protocol, otherwise there is no way to define which agent is processing the measure. This mechanism allows
> smart systems to connect different devices to different IoT Agents according to need.
>
> For southbound commands, this distinction is unnecessary since the correct IoT Agent has already
> registered itself for the command during the device provisioning step and the device will always
> receive commands in an appropriate format.
> For southbound commands, this distinction is unnecessary since the correct IoT Agent has already registered itself for
> the command during the device provisioning step and the device will always receive commands in an appropriate format.
This transport protocol binding is still under development.

Expand Down Expand Up @@ -375,7 +371,8 @@ commands and a topic to receive configuration information. This mechanism can be
configuration flag, `configRetrieval`.

In case of MQTT to retrieve configuration parameters from the Context Broker, it is required that the device should be
provisioned using "MQTT" as transport key. By default it will be considered "HTTP" as transport.
provisioned using "MQTT" as transport key, at device or group level. By default it will be considered "HTTP" as
transport.

The parameter will be given as follows:

Expand Down
10 changes: 7 additions & 3 deletions lib/bindings/HTTPBindings.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ const config = require('../configService');
let context = {
op: 'IOTAUL.HTTP.Binding'
};
const transport = 'HTTP';

/* eslint-disable-next-line no-unused-vars */
function handleError(error, req, res, next) {
Expand All @@ -67,7 +66,7 @@ function parseData(req, res, next) {
let data;
let error;
let payload;

context = fillService(context, { service: 'n/a', subservice: 'n/a' });
if (req.body) {
payload = req.body;
} else {
Expand Down Expand Up @@ -264,7 +263,7 @@ function handleIncomingMeasure(req, res, next) {
}
}

utils.retrieveDevice(req.deviceId, req.apiKey, /*transport,*/ processDeviceMeasure);
utils.retrieveDevice(req.deviceId, req.apiKey, processDeviceMeasure);
}

/**
Expand All @@ -278,6 +277,7 @@ function handleIncomingMeasure(req, res, next) {
function generateCommandExecution(apiKey, device, attribute) {
const cmdName = attribute.name;
const cmdAttributes = attribute.value;
context = fillService(context, device);
const options = {
url: device.endpoint,
method: 'POST',
Expand Down Expand Up @@ -360,6 +360,7 @@ function generateCommandExecution(apiKey, device, attribute) {
* @param {String} attributes Command attributes (in NGSIv1 format).
*/
function commandHandler(device, attributes, callback) {
context = fillService(context, device);
utils.getEffectiveApiKey(device.service, device.subservice, device, function (error, apiKey) {
async.series(attributes.map(generateCommandExecution.bind(null, apiKey, device)), function (error) {
if (error) {
Expand Down Expand Up @@ -404,6 +405,7 @@ function addDefaultHeader(req, res, next) {
* @param {Object} device Device object containing all the information about the provisioned device.
*/
function setPollingAndDefaultTransport(device, group, callback) {
context = fillService(context, device);
config.getLogger().debug(context, 'httpbinding.setPollingAndDefaultTransport device %j group %j', device, group);
if (!device.transport) {
device.transport = group && group.transport ? group.transport : 'HTTP';
Expand All @@ -426,6 +428,7 @@ function setPollingAndDefaultTransport(device, group, callback) {
* @param {Object} device Device object containing all the information about the provisioned device.
*/
function deviceProvisioningHandler(device, callback) {
context = fillService(context, device);
config.getLogger().debug(context, 'httpbinding.deviceProvisioningHandler %j', device);
let group = {};
iotAgentLib.getConfigurationSilently(config.getConfig().iota.defaultResource || '', device.apikey, function (
Expand All @@ -446,6 +449,7 @@ function deviceProvisioningHandler(device, callback) {
* @param {Object} device Device object containing all the information about the updated device.
*/
function deviceUpdatingHandler(device, callback) {
context = fillService(context, device);
config.getLogger().debug(context, 'httpbinding.deviceUpdatingHandler %j', device);
let group = {};
iotAgentLib.getConfigurationSilently(config.getConfig().iota.defaultResource || '', device.apikey, function (
Expand Down
8 changes: 4 additions & 4 deletions lib/commonBindings.js
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ function singleMeasure(apiKey, attribute, device, messageStr, message) {
* @param {String} topic Topic of the form: '/<APIKey>/deviceId/attributes[/<attributeName>]'.
* @param {Object} message message body (Object or Buffer, depending on the value).
*/
function messageHandler(topic, message /*, protocol*/) {
function messageHandler(topic, message) {
if (topic[0] !== '/') {
topic = '/' + topic;
}
Expand Down Expand Up @@ -329,7 +329,7 @@ function messageHandler(topic, message /*, protocol*/) {
}
}

utils.retrieveDevice(deviceId, apiKey, /*protocol,*/ processDeviceMeasure);
utils.retrieveDevice(deviceId, apiKey, processDeviceMeasure);
}

/**
Expand All @@ -341,7 +341,7 @@ function messageHandler(topic, message /*, protocol*/) {
*/
function amqpMessageHandler(topic, message) {
regenerateTransid(topic);
messageHandler(topic, message /*, 'AMQP'*/);
messageHandler(topic, message);
}

/**
Expand All @@ -354,7 +354,7 @@ function amqpMessageHandler(topic, message) {
function mqttMessageHandler(topic, message) {
regenerateTransid(topic);
config.getLogger().debug(context, 'message topic: %s', topic);
messageHandler(topic, message /*, 'MQTT'*/);
messageHandler(topic, message);
}

exports.amqpMessageHandler = amqpMessageHandler;
Expand Down
74 changes: 2 additions & 72 deletions lib/iotaUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,84 +62,14 @@ function getEffectiveApiKey(service, subservice, device, callback) {
}
}

// function findOrCreate(deviceId, transport, apikey, group, callback) {
// iotAgentLib.getDeviceSilently(deviceId, apikey, group.service, group.subservice, function (error, device) {
// if (!error && device) {
// if (
// (!('apikey' in device) || device.apikey === undefined) &&
// 'apikey' in group &&
// group.apikey !== undefined
// ) {
// config
// .getLogger()
// .info(context, 'Update provisioned device %j with measure/group apikey %j', device, group.apikey);
// device.apikey = group.apikey; // group apikey is the same of current measure apikey
// iotAgentLib.updateDevice(device, function (error) {
// callback(error, device, group);
// });
// } else {
// callback(null, device, group);
// }
// } else if (error.name === 'DEVICE_NOT_FOUND') {
// const newDevice = {
// id: deviceId,
// service: group.service,
// subservice: group.subservice,
// type: group.type
// };

// if (
// config.getConfig().iota &&
// config.getConfig().iota.iotManager &&
// config.getConfig().iota.iotManager.protocol
// ) {
// newDevice.protocol = config.getConfig().iota.iotManager.protocol;
// }

// // Fix transport depending on binding
// if (!newDevice.transport) {
// newDevice.transport = transport;
// }
// if ('ngsiVersion' in group && group.ngsiVersion !== undefined) {
// newDevice.ngsiVersion = group.ngsiVersion;
// }
// if (
// (!('apikey' in newDevice) || newDevice.apikey === undefined) &&
// 'apikey' in group &&
// group.apikey !== undefined
// ) {
// newDevice.apikey = group.apikey;
// }
// // Check autoprovision flag in order to register or not device
// if (group.autoprovision === undefined || group.autoprovision === true) {
// iotAgentLib.register(newDevice, function (error, device) {
// callback(error, device, group);
// });
// } else {
// config
// .getLogger()
// .info(
// context,
// 'Device %j not provisioned due autoprovision is disabled by its conf %j',
// newDevice,
// group
// );
// callback(new errors.DeviceNotFound(deviceId));
// }
// } else {
// callback(error);
// }
// });
// }

/**
* Retrieve a device from the device repository based on the given APIKey and DeviceID, creating one if none is
* found for the given data.
*
* @param {String} deviceId Device ID of the device that wants to be retrieved or created.
* @param {String} apiKey APIKey of the Device Group (or default APIKey).
*/
function retrieveDevice(deviceId, apiKey, /*transport,*/ callback) {
function retrieveDevice(deviceId, apiKey, callback) {
if (apiKey === config.getConfig().defaultKey) {
iotAgentLib.getDevicesByAttribute('id', deviceId, undefined, undefined, function (error, devices) {
if (error) {
Expand All @@ -163,7 +93,7 @@ function retrieveDevice(deviceId, apiKey, /*transport,*/ callback) {
async.waterfall(
[
apply(iotAgentLib.getConfigurationSilently, config.getConfig().iota.defaultResource, apiKey),
apply(iotAgentLib.findOrCreate, deviceId, /* transport,*/ apiKey), // group.apikey and apikey are the same
apply(iotAgentLib.findOrCreate, deviceId, apiKey), // group.apikey and apikey are the same
apply(
iotAgentLib.mergeDeviceWithConfiguration,
['lazy', 'active', 'staticAttributes', 'commands', 'subscriptions'],
Expand Down
30 changes: 24 additions & 6 deletions lib/iotagent-ul.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,30 @@ function commandHandler(id, type, service, subservice, attributes, callback) {
);
callback(error);
} else {
transportSelector.applyFunctionFromBinding(
[device, attributes],
'commandHandler',
device.transport || config.getConfig().defaultTransport,
callback
);
iotaUtils.getEffectiveApiKey(device.service, device.subservice, device, function (error, apiKey) {
if (error) {
callback(error);
} else {
let group = {};
iotAgentLib.getConfigurationSilently(
config.getConfig().iota.defaultResource || '',
apiKey,
function (error, foundGroup) {
if (!error) {
group = foundGroup;
}
transportSelector.applyFunctionFromBinding(
[device, attributes],
'commandHandler',
device.transport ||
(group && group.transport ? group.transport : undefined) ||
config.getConfig().defaultTransport,
callback
);
}
);
}
});
}
});
}
Expand Down

0 comments on commit 26dd0bc

Please sign in to comment.