iotagent-node-lib
Version:
IoT Agent library to interface with NGSI Context Broker
1,340 lines (926 loc) • 76.5 kB
Markdown
# Development documentation
- [Preface](#preface)
- [Contributing](#contributing)
- [Project management](#project-management)
- [Installing dependencies](#installing-dependencies)
- [Project build](#project-build)
- [Testing](#testing)
- [Test requirements](#test-requirements)
- [Debug Test](#debug-test)
- [Continuous testing](#continuous-testing)
- [Code Coverage](#code-coverage)
- [Clean](#clean)
- [Checking code style](#checking-code-style)
- [Source code style validation - ESLint](#source-code-style-validation---eslint)
- [Documentation Markdown validation](#documentation-markdown-validation)
- [Documentation Spell-checking](#documentation-spell-checking)
- [Prettify Code](#prettify-code)
- [Library functions and modules](#library-functions-and-modules)
- [Stats Registry](#stats-registry)
- [Alarm module](#alarm-module)
- [Transactions](#transactions)
- [Library overview](#library-overview)
- [Function reference](#function-reference)
- [Generic middlewares](#generic-middlewares)
- [DB Models from API document](#db-models-from-api-document)
- [Config group model](#config-group-model)
- [Device model](#device-model)
- [Developing a new IoT Agent](#developing-a-new-iot-agent)
- [Protocol](#protocol)
- [Requirements](#requirements)
- [Basic IOTA](#basic-iot-agent)
- [IOTA With Active attributes](#iot-agent-with-active-attributes)
- [IOTA With Lazy attributes](#iota-with-lazy-attributes)
- [Previous considerations](#previous-considerations)
- [Implementation](#implementation)
- [IoT Agent in multi-thread mode](#iot-agent-in-multi-thread-mode)
- [Configuration management](#configuration-management)
- [Provisioning handlers](#provisioning-handlers)
- [IoT Agent additional tools](#iot-agent-additional-tools)
## Preface
The **IoT Agent node library** as the name suggests is a library that provides a set of functions that can be used by
IoT Agents to implement the northbound interface. The library is used by several FIWARE IoT Agents, such as:
a standalone library that can be used by any IoT Agent to implement the northbound interface,
is not a standalone product and should be added as a dependency to `package.json` of the IoT Agent.
```json
...
"dependencies": {
"iotagent-node-lib": "*",
}
```
In order to use the library within your own IoT Agent, you must first you require it before use:
```javascript
const iotagentLib = require('iotagent-node-lib');
```
This file contains the documentation for developers who wish to contribute to the **IoT Agent node library** project and
also for those who wish to use the library within their own IoT Agent project.
## Contributing
Contributions to this project are welcome. Developers planning to contribute should follow the
[Contribution Guidelines](contribution-guidelines.md)
## Project management
The **IoT Agent node library** project is managed using [npm](https://www.npmjs.com/). The following sections show the
available options in detail:
### Installing dependencies
This is the first step to be executed after cloning the project. To install them, type the following command:
```bash
npm install
```
### Project build
The project is managed using npm.
For a list of available task, type
```bash
npm run
```
The following sections show the available options in detail.
### Testing
[Mocha](https://mochajs.org/) Test Runner + [Should.js](https://shouldjs.github.io/) Assertion Library.
The test environment is preconfigured to run BDD testing style.
Module mocking during testing can be done with [proxyquire](https://github.com/thlorenz/proxyquire)
To run tests, type
```bash
npm test
```
There are additional targets starting with `test:` prefix to run specific test subsets isolated. For instance, the
`test:expressions` target runs the subset of tests related with expression language feature:
```bash
npm run test:expressions
```
#### Test requirements
A [MongoDB](https://www.mongodb.com/) 3.2+ instance is required to run tests. You can deploy one by using the commodity
`docker-compose-dev.yml`:
```
docker-compose -f docker-compose-dev.yml up -d
```
To run docker compose you will need [docker](https://docs.docker.com/get-docker/) and
[docker-compose](https://docs.docker.com/compose/install/).
#### Debug Test
To debug the code while running run tests, type
```bash
npm run test:debug
```
In the console the link to the debugger will be provided. You can connect to it via Chrome, for example, by opening the
following url: `chrome://inspect`.
Additional debug clients are listed on [node.js](https://nodejs.org/en/docs/guides/debugging-getting-started/).
#### Continuous testing
Support for continuous testing by modifying a src file or a test. For continuous testing, type
```bash
npm run test:watch
```
If you want to continuously check also source code style, use instead:
```bash
npm run watch
```
#### Code Coverage
Istanbul
Analyze the code coverage of your tests.
To generate an HTML coverage report under `site/coverage/` and to print out a summary, type
```bash
# Use git-bash on Windows
npm run test:coverage
```
### Clean
Removes `node_modules` and `coverage` folders, and `package-lock.json` file so that a fresh copy of the project is
restored.
```bash
# Use git-bash on Windows
npm run clean
```
### Checking code style
#### Source code style validation - ESLint
Uses the provided `.eslintrc.json` flag file. To check source code style, type
```bash
npm run lint
```
#### Documentation Markdown validation
Checks the Markdown documentation for consistency
```bash
# Use git-bash on Windows
npm run lint:md
```
#### Documentation Spell-checking
Uses the provided `.textlintrc` flag file. To check the Markdown documentation for spelling and grammar errors, dead
links & etc.
```bash
# Use git-bash on Windows
npm run lint:text
```
#### Prettify Code
Runs the [prettier](https://prettier.io) code formatter to ensure consistent code style (whitespacing, parameter
placement and breakup of long lines etc.) within the codebase.
```bash
# Use git-bash on Windows
npm run prettier
```
To ensure consistent Markdown formatting run the following:
```bash
# Use git-bash on Windows
npm run prettier:text
```
## Library functions and modules
### Stats Registry
The library provides a mechanism for the collection of stats related to the library's work. The Stats Registry holds a
dictionary with the historical global value of each stat.
The stats library currently stores only the following values:
- **deviceCreationRequests**: number of Device Creation Requests that arrived to the API (no matter the result).
- **deviceRemovalRequests**: number of Removal Device Requests that arrived to the API (no matter the result).
- **measureRequests**: number of times the ngsiService.update() function has been invoked (no matter the result).
- **raiseAlarm**: number of times the alarmManagement.raise() function has been invoked.
- **releaseAlarm**: number of times the alarmManagement.release() function has been invoked.
- **updateEntityRequestsOk**: number of times the ngsiService.sendUpdateValue() function has been invoked
successfully.
- **updateEntityRequestsError**: number of times the ngsiService.sendUpdateValue() function has been invoked and
failed.
More values will be added in the future to the library. The applications using the library can add values to the Stats
Registry just by using the following function:
```javascript
iotagentLib.statsRegistry.add('statName', statIncrementalValue, callback);
```
The first time this function is invoked, it will add the new stat to the registry. Subsequent calls will add the value
to the specified stat.
### Alarm module
The library provide an alarm module that can be used to track through the logs alarms raised in the IoTAgent. This
module provides:
- Two functions to raise and release and alarm (`raise()` and `release()`): every alarm is identified by a name and a
description. When the alarm is raised, an error with the text `Raising [%s]` is logged. When the alarm is released,
the corresponding text, `Releasing [%s]` is logged. If an alarm is raised multiple times, it is only logged once. If
its released multiple times it is only released once. Releasing a non-existing alarm has no effect.
- Functions to list all the raised alarms and clean all the alarms (`list()` and `clean()`).
- A function to instrument other functions, so when one of that functions return an error, an alarm is raised, and
when it returns a success an alarm is ceased (`intercept()`).
All this functions can be accessed through the `.alarms` attribute of the library.
### Transactions
The library implements a concept of transactions, in order to follow the execution flow the library follows when
treating requests entering both from the North and the South ports of the IoT Agent.
To follow the transactions, a new Domain is created for each incoming request; in the case of requests received on the
North Port of the IoT Agent, this domain is automatically created by a Express middleware, and no further action is
needed from the user. For the case of requests received on the South Port of the IoT Agent, the user is responsible of
creating an stopping the transaction, using the `ensureSouthboundDomain` and `finishSouthBoundTransaction`. In this
case, the transaction will last from the invocation to the former to the invocation of the latter.
The Transaction Correlator is used along all the IoT Platform to follow the trace of a transaction between multiple
components. To do so, in all the HTTP requests sent to other components of the platform, a custom header named
`Fiware-Correlator` is sent with the correlator of the transaction that generated the request. If a component of the
platform receives a request containing this header that starts a transaction, the component will create the transaction
with the received correlator, instead of creating a new one. If the header is not present or the transaction originates
in the component, the transaction ID in this component will be used as the correlator.
During the duration of a transaction, all the log entries created by the code will write the current Transaction ID and
correlator for the operation being executed.
### Library overview
In order to use the library, add the following dependency to your package.json file:
```json
"iotagent-node-lib": "*"
```
In order to use this library, first you must require it:
```javascript
var iotagentLib = require('iotagent-node-lib');
```
The library supports four groups of features, one for each direction of the communication: client-to-server and
server-to-client (and each flow both for the client and the server). Each feature set is defined in the following
sections.
### Function reference
> **WARNING** This section is outdated. Functions described here may be outdated and not reflect the current
> implementation of the IoT Agent Library. You could have a look to [iotagentLib.js](./lib/iotagentLib.js) file to see
> the current detail of functions implemented.
The following fucntions are available in the library:
- [iotagentLib.activate()](#iotagentlibactivate)
- [iotagentLib.deactivate()](#iotagentlibdeactivate)
- [iotagentLib.register()](#iotagentlibregister)
- [iotagentLib.unregister()](#iotagentlibunregister)
- [iotagentLib.update()](#iotagentlibupdate)
- [iotagentLib.setCommandResult()](#iotagentlibsetcommandresult)
- [iotagentLib.listDevices()](#iotagentliblistdevices)
- [iotagentLib.setDataUpdateHandler()](#iotagentlibsetdataupdatehandler)
- [iotagentLib.setDataQueryHandler()](#iotagentlibsetdataqueryhandler)
- [iotagentLib.setNotificationHandler()](#iotagentlibsetnotificationhandler)
- [iotagentLib.setCommandHandler()](#iotagentlibsetcommandhandler)
- [iotagentLib.setMergePatchHandler()](#iotagentlibsetmergepatchhandler)
- [iotagentLib.setProvisioningHandler()](#iotagentlibsetprovisioninghandler)
- [iotagentLib.setRemoveDeviceHandler()](#iotagentlibsetremovedevicehandler)
- [iotagentLib.setConfigurationHandler()](#iotagentlibsetconfigurationhandler)
- [iotagentLib.setRemoveConfigurationHandler()](#iotagentlibsetremoveconfigurationhandler)
- [iotagentLib.getDevice()](#iotagentlibgetdevice)
- [iotagentLib.getDeviceByName()](#iotagentlibgetdevicebyname)
- [iotagentLib.getDevicesByAttribute()](#iotagentlibgetdevicesbyattribute)
- [iotagentLib.retrieveDevice()](#iotagentlibretrievedevice)
- [iotagentLib.mergeDeviceWithConfiguration()](#iotagentlibmergedevicewithconfiguration)
- [iotagentLib.getConfiguration()](#iotagentlibgetconfiguration)
- [iotagentLib.findConfiguration()](#iotagentlibfindconfiguration)
- [iotagentLib.getEffectiveApiKey()](#iotagentlibgeteffectiveapikey)
- [iotagentLib.subscribe()](#iotagentlibsubscribe)
- [iotagentLib.unsubscribe()](#iotagentlibunsubscribe)
- [iotagentLib.ensureSouthboundDomain()](#iotagentlibensuresouthbounddomain)
- [iotagentLib.finishSouthBoundTransaction()](#iotagentlibfinishsouthboundtransaction)
- [iotagentLib.startServer()](#iotagentlibstartserver)
- [iotagentLib.request()](#iotagentlibrequest)
##### iotagentLib.activate()
###### Signature
```javascript
function activate(newConfig, callback)
```
###### Description
Activates the IoT Agent to start listening for NGSI Calls (acting as a Context Provider). It also creates the device
registry for the IoT Agent (based on the deviceRegistry.type configuration option).
###### Params
- newConfig: Configuration of the Context Server (described in the [Configuration](../admin.md#configuration)
section).
##### iotagentLib.deactivate()
###### Signature
```javascript
function deactivate(callback)
```
###### Description
Stops the HTTP server.
###### Params
##### iotagentLib.register()
###### Signature
```javascript
function registerDevice(deviceObj, callback)
```
###### Description
Register a new device in the IoT Agent. This registration will also trigger a Context Provider registration in the
Context Broker for all its lazy attributes.
The device Object can have the following attributes:
- `id`: Device ID of the device.
- `type`: type to be assigned to the device.
- `name`: name that will be used for the Entity representing the device in the Context Broker.
- `service`: name of the service associated with the device.
- `subservice`: name of the subservice associated with th device.
- `lazy`: list of lazy attributes with their types.
- `active`: list of active attributes with their types.
- `staticAttributes`: list of NGSI attributes to add to the device entity 'as is' in updates, queries and
registrations.
- `internalAttributes`: optional section with free format, to allow specific IoT Agents to store information along
with the devices in the Device Registry.
The device `id` and `type` are required fields for any registration. The rest of the attributes are optional, but, if
they are not present in the function call arguments, the type must be registered in the configuration, so the service
can infer their default values from the configured type. If an optional attribute is not given in the parameter list and
there isn't a default configuration for the given type, a TypeNotFound error is raised.
If the device has been previously preprovisioned, the missing data will be completed with the values from the registered
device.
###### Params
- deviceObj: object containing all the information about the device to be registered (mandatory).
##### iotagentLib.unregister()
###### Signature
```javascript
function unregisterDevice(id, service, subservice, callback)
```
###### Description
Unregister a device from the Context broker and the internal registry.
###### Params
- id: Device ID of the device to register.
- service: Service of the device to unregister.
- subservice: Subservice inside the service for the unregistered device.
##### iotagentLib.update()
###### Signature
```javascript
function update(entityName, attributes, typeInformation, token, callback)
```
###### Description
Makes an update in the Device's entity in the context broker, with the values given in the 'attributes' array. This
array should comply to the NGSI's attribute format.
###### Params
- entityName: Name of the entity to register.
- attributes: Attribute array containing the values to update.
- typeInformation: Configuration information for the device.
- token: User token to identify against the PEP Proxies (optional).
##### iotagentLib.setCommandResult()
###### Signature
```javascript
function setCommandResult(entityName, resource, apikey, commandName, commandResult, status, deviceInformation, callback)
```
###### Description
Update the result of a command in the Context Broker. The result of the command has two components: the result of the
command itself will be represented with the suffix `_info` in the entity while the status is updated in the attribute
with the `_status` suffix.
###### Params
- entityName: Name of the entity holding the command.
- resource: Resource name of the endpoint the device is calling.
- apikey: Apikey the device is using to send the values (can be the empty string if none is needed).
- commandName: Name of the command whose result is being updated.
- commandResult: Result of the command in string format.
- deviceInformation: Device information, including security and service information. (optional).
##### iotagentLib.listDevices()
###### Signature
```javascript
function listDevices(callback)
function listDevices(limit, offset, callback)
function listDevices(service, subservice, limit, offset, callback)
```
###### Description
Return a list of all the devices registered in the specified service and subservice. This function can be invoked in
three different ways:
- with just one parameter (the callback)
- with three parameters (service, subservice and callback)
- or with five parameters (including limit and offset).
###### Params
- service: service from where the devices will be retrieved.
- subservice: subservice from where the devices will be retrieved.
- limit: maximum number of results to retrieve (optional).
- offset: number of results to skip from the listing (optional).
##### iotagentLib.setDataUpdateHandler()
###### Signature
```javascript
function setDataUpdateHandler(newHandler)
```
###### Description
Sets the new user handler for Entity update requests. This handler will be called whenever an update request arrives
with the following parameters: (`id`, `type`, `service`, `subservice`, `attributes`, `callback`). Every object within of
the `attributes` array contains `name`, `type` and `value` attributes, and may also include additional attributes for
`metadata` and `datasetId`. The handler is in charge of updating the corresponding values in the devices with the
appropriate protocol.
Once all the updates have taken place, the callback must be invoked with the updated Context Element. E.g.:
```javascript
callback(null, {
type: 'TheType',
isPattern: false,
id: 'EntityID',
attributes: [
{
name: 'lumniscence',
type: 'Lumens',
value: '432'
}
]
});
```
In the case of NGSI requests affecting multiple entities, this handler will be called multiple times, one for each
entity, and all the results will be combined into a single response.
###### Params
- newHandler: User handler for update requests
##### iotagentLib.setDataQueryHandler()
###### Signature
```javascript
function setDataQueryHandler(newHandler)
```
###### Description
Sets the new user handler for Entity query requests. This handler will be called whenever a query request arrives, with
the following parameters: (`id`, `type`, `service`, `subservice`, `attributes`, `callback`). The handler must retrieve
all the corresponding information from the devices and return a NGSI entity with the requested values.
The callback must be invoked with the updated Context Element, using the information retrieved from the devices. E.g.:
```javascript
callback(null, {
type: 'TheType',
isPattern: false,
id: 'EntityID',
attributes: [
{
name: 'lumniscence',
type: 'Lumens',
value: '432'
}
]
});
```
In the case of NGSI requests affecting multiple entities, this handler will be called multiple times, one for each
entity, and all the results will be combined into a single response.
###### Params
- newHandler: User handler for query requests.
##### iotagentLib.setNotificationHandler()
###### Signature
```javascript
function setNotificationHandler(newHandler)
```
###### Description
Sets the new handler for incoming notifications. The notifications are sent by the Context Broker based on the IoT Agent
subscriptions created with the `subscribe()` function.
The handler must adhere to the following signature:
```javascript
function mockedHandler(device, data, callback)
```
The `device` parameter contains the device object corresponding to the entity whose changes were notified with the
incoming notification. Take into account that multiple entities may be modified with each single notification. The
handler will be called once for each one of those entities.
The `data` parameter is an array with all the attributes that were requested in the subscription and its respective
values.
The handler is expected to call its callback once with no parameters (failing to do so may cause unexpected behaviors in
the IoT Agent).
##### iotagentLib.setCommandHandler()
###### Signature
```javascript
function setCommandHandler(newHandler)
```
###### Description
Sets the new user handler for registered entity commands. This handler will be called whenever a command request
arrives, with the following parameters: (`id`, `type`, `service`, `subservice`, `attributes`, `callback`). The handler
must retrieve all the corresponding information from the devices and return a NGSI entity with the requested values.
The callback must be invoked with the updated Context Element, using the information retrieved from the devices. E.g.:
```javascript
callback(null, {
type: 'TheType',
isPattern: false,
id: 'EntityID',
attributes: [
{
name: 'lumniscence',
type: 'Lumens',
value: '432'
}
]
});
```
In the case of NGSI requests affecting multiple entities, this handler will be called multiple times, one for each
entity, and all the results will be combined into a single response. Only IoT Agents which deal with actuator devices
will include a handler for commands.
###### Params
- newHandler: User handler for command requests.
##### iotagentLib.setMergePatchHandler()
###### Signature
```javascript
function setMergePatchHandler(newHandler)
```
###### Description
Sets the new user handler for NGSI-LD Entity [merge-patch](https://datatracker.ietf.org/doc/html/rfc7386) requests. This
handler will be called whenever a merge-patch request arrives, with the following parameters: (`id`, `type`, `service`,
`subservice`, `attributes`, `callback`). The handler must retrieve all the corresponding information from the devices
and return a NGSI entity with the requested values.
The callback must be invoked with the updated Context Element, using the information retrieved from the devices. E.g.:
```javascript
callback(null, {
type: 'TheType',
isPattern: false,
id: 'EntityID',
attributes: [
{
name: 'lumniscence',
type: 'Lumens',
value: '432'
}
]
});
```
In the case of NGSI-LD requests affecting multiple entities, this handler will be called multiple times. Since
merge-patch is an advanced function, not all IoT Agents will include a handler for merge-patch.
###### Params
- newHandler: User handler for merge-patch requests.
##### iotagentLib.setProvisioningHandler()
###### Signature
```javascript
function setProvisioningHandler (newHandler)
```
###### Description
Sets the new user handler for the provisioning of devices. This handler will be called every time a new device is
created.
The handler must adhere to the following signature:
```javascript
function(newDevice, callback)
```
The `newDevice` parameter will contain the newly created device. The handler is expected to call its callback with no
parameters (this handler should only be used for reconfiguration purposes of the IoT Agent).
##### iotagentLib.setRemoveDeviceHandler()
###### Signature
```javascript
function setRemoveDeviceHandler(newHandler)
```
###### Description
Sets the new user handler for the removal of a device. This handler will be called every time a device is removed.
The handler must adhere to the following signature:
```javascript
function(deviceToDelete, callback)
```
The `deviceToDelete` parameter will contain the device to be deleted. The handler is expected to call its callback with
no parameters (this handler should only be used for reconfiguration purposes of the IoT Agent).
##### iotagentLib.setConfigurationHandler()
###### Signature
```javascript
function setConfigurationHandler(newHandler)
```
###### Description
Sets the new user handler for the configuration updates. This handler will be called every time a new configuration is
created or an old configuration is updated.
The handler must adhere to the following signature:
```javascript
function(newConfiguration, callback)
```
The `newConfiguration` parameter will contain the newly created configuration. The handler is expected to call its
callback with no parameters (this handler should only be used for reconfiguration purposes of the IoT Agent).
For the cases of multiple updates (a single Device Configuration POST that will create several device groups), the
handler will be called once for each of the config groups (both in the case of the creations and the updates).
The handler will be also called in the case of updates related to config groups. In that situation, the
`newConfiguration` parameter contains also the fields needed to identify the configuration to be updated, i.e.,
`service`, `subservice`, `resource` and `apikey`.
##### iotagentLib.setRemoveConfigurationHandler()
###### Signature
```javascript
function setRemoveConfigurationHandler(newHandler)
```
###### Description
Sets the new user handler for the removal of configuratios. This handler will be called every time a configuration is
removed.
The handler must adhere to the following signature:
```javascript
function(configurationToDelete, callback)
```
The `configurationToDelete` parameter will contain the configuration to be deleted. The handler is expected to call its
callback with no parameters (this handler should only be used for reconfiguration purposes of the IoT Agent).
##### iotagentLib.getDevice()
###### Signature
```javascript
function getDevice(deviceId, service, subservice, callback)
```
###### Description
Retrieve all the information about a device from the device registry.
###### Params
- deviceId: ID of the device to be found.
- service: Service for which the requested device.
- subservice: Subservice inside the service for which the device is requested.
##### iotagentLib.getDeviceByName()
###### Signature
```javascript
function getDeviceByName(deviceName, service, subservice, callback)
```
###### Description
Retrieve a device from the registry based on its entity name.
###### Params
- deviceName: Name of the entity associated to a device.
- service: Service the device belongs to.
- subservice: Division inside the service.
##### iotagentLib.getDevicesByAttribute()
###### Signature
```javascript
function getDevicesByAttribute(attributeName, attributeValue, service, subservice, callback)
```
###### Description
Retrieve all the devices having an attribute named `name` with value `value`.
###### Params
- name: name of the attribute to match.
- value: value to match in the attribute.
- service: Service the device belongs to.
- subservice: Division inside the service.
##### iotagentLib.retrieveDevice()
###### Signature
```javascript
function retrieveDevice(deviceId, apiKey, callback)
```
###### Description
Retrieve a device from the device repository based on the given APIKey and DeviceID, creating one if none is found for
the given data.
###### Params
- deviceId: Device ID of the device that wants to be retrieved or created.
- apiKey: APIKey of the Device Group (or default APIKey).
##### iotagentLib.mergeDeviceWithConfiguration()
###### Signature
```javascript
function mergeDeviceWithConfiguration(fields, defaults, deviceData, configuration, callback)
```
###### Description
Complete the information of the device with the information in the configuration group (with precedence of the device).
The first argument indicates what fields would be merged.
###### Params
- fields: Fields that will be merged.
- defaults: Default values fot each of the fields.
- deviceData: Device data.
- configuration: Configuration data.
##### iotagentLib.getConfiguration()
###### Signature
```javascript
function getConfiguration(resource, apikey, callback)
```
###### Description
Gets the device group identified by the given (`resource`, `apikey`) pair.
###### Params
- resource: representation of the configuration in the IoT Agent (dependent on the protocol) .
- apikey: special key the devices will present to prove they belong to a particular configuration.
##### iotagentLib.findConfiguration()
###### Signature
```javascript
function findConfiguration(service, subservice, callback)
```
###### Description
Find a device group based on its service and subservice.
###### Params
- service: name of the service of the configuration.
- subservice: name of the subservice of the configuration.
##### iotagentLib.getEffectiveApiKey()
###### Signature
```javascript
function getEffectiveApiKey(service, subservice, type, callback)
```
###### Description
Get the API Key for the selected service if there is any, or the default API Key if a specific one does not exist.
###### Params
- service: Name of the service whose API Key we are retrieving.
- subservice: Name of the subservice whose API Key we are retrieving.
- type: Type of the device.
##### iotagentLib.subscribe()
###### Signature
```javascript
function subscribe(device, triggers, content, callback)
```
###### Description
Creates a subscription for the IoTA to the entity representing the selected device.
###### Params
- device: Object containing all the information about a particular device.
- triggers: Array with the names of the attributes that would trigger the subscription
- content: Array with the names of the attributes to retrieve in the notification.
##### iotagentLib.unsubscribe()
###### Signature
```javascript
function unsubscribe(device, id, callback)
```
###### Description
Removes a single subscription from the selected device, identified by its ID.
###### Params
- `device`: Object containing all the information about a particular device.
- `id`: ID of the subscription to remove.
##### iotagentLib.ensureSouthboundDomain()
###### Signature
```javascript
function ensureSouthboundTransaction(context, callback)
```
###### Description
Ensures that the current operation is executed inside a transaction with all the information needed for the appropriate
platform logging: start date, transaction ID and correlator in case one is needed. If the function is executed in the
context of a previous transaction, just the context is changed (and the Transaction ID and start time are kept).
###### Params
- context: New context data for the transaction.
##### iotagentLib.finishSouthBoundTransaction()
###### Signature
```javascript
function finishSouthboundTransaction(callback)
```
###### Description
Terminates the current transaction, if there is any, cleaning its context.
##### iotagentLib.startServer()
###### Signature
```javascript
function startServer(newConfig, iotAgent, callback)
```
###### Description
Start the HTTP server either in single-thread or multi-thread (multi-core) based on the value of _multiCore_ variable
(described in the [Configuration](../admin.md#configuration) section). If the value is `False` (either was directly
specified `False` in the `config.js` or it was not specified and by default is assigned `False`), it is a normal
(single-thread) behaviour. Nevertheless, if _multiCore_ is `True`, the IoTAgent is executed in multi-thread environment.
The number of parallel processes is calculated based on the number of available CPUs. In case of some of the process
unexpectedly dead, a new process is created automatically to keep always the maximum of them working in parallel.
> Note: `startServer()` initializes the server but it does not activate the library. The function in the Node Lib will
> call the `iotAgent.start()` in order to complete the activation of the library. Therefore, it is expected that the IoT
> Agent implement the `iotAgent.start()` function with the proper invocation to the `iotAgentLib.activate()`.
###### Params
- newConfig: Configuration of the Context Server (described in the [Configuration](../admin.md#configuration)
section).
- iotAgent: The IoT Agent Objects, used to start the agent.
- callback: The callback function.
##### iotagentLib.request()
###### Signature
```javascript
function request(options, callback)
```
###### Description
Make a direct HTTP request using the underlying request library (currently [got](https://github.com/sindresorhus/got)),
this is useful when creating agents which use an HTTP transport for their southbound commands, and removes the need for
the custom IoT Agent to import its own additional request library
###### Params
- options: definition of the request (see
[got options](https://github.com/sindresorhus/got/blob/main/documentation/2-options.md) for more details). The
following attributes are currently exposed.
- `method` - HTTP Method
- `searchParams` - query string params
- `qs` - alias for query string params
- `headers`
- `responseType` - either `text` or `json`. `json` is the default
- `json` - a supplied JSON object as the request body
- `body` - any ASCII text as the request body. It takes precedence over `json` if both are provided at the same
time (not recommended).
- `url` - the request URL
- `uri` - alternative alias for the request URL.
- callback: The callback currently returns an `error` Object, the `response` and `body`. The `body` is parsed to a
JSON object if the `responseType` is JSON.
#### Generic middlewares
This collection of utility middlewares is aimed to be used to north of the IoT Agent Library, as well as in other
HTTP-based APIs of the IoT Agents. All the middlewares follow the Express convention of `(req, res, next)` objects, so
this information will not be repeated in the descriptions for the middleware functions. All the middlewares can be added
to the servers using the standard Express mechanisms.
##### iotagentLib.middlewares.handleError()
###### Signature
```javascript
function handleError(error, req, res, next)
```
###### Description
Express middleware for handling errors in the IoTAs. It extracts the code information to return from the error itself
returning 500 when no error code has been found.
##### iotagentLib.middlewares.traceRequest()
###### Signature
```javascript
function traceRequest(req, res, next)
```
###### Description
Express middleware for tracing the complete request arriving to the IoTA in debug mode.
##### iotagentLib.middlewares.changeLogLevel()
###### Signature
```javascript
function changeLogLevel(req, res, next)
```
###### Description
Changes the log level to the one specified in the request.
##### iotagentLib.middlewares.ensureType()
###### Signature
```javascript
function ensureType(req, res, next)
```
###### Description
Ensures the request type is one of the supported ones.
##### iotagentLib.middlewares.validateJson()
###### Signature
```javascript
function validateJson(template)
```
###### Description
Generates a Middleware that validates incoming requests based on the JSON Schema template passed as a parameter.
Returns an Express middleware used in request validation with the given template.
###### Params
- _template_: JSON Schema template to validate the request.
##### iotagentLib.middlewares.retrieveVersion()
###### Signature
```javascript
function retrieveVersion(req, res, next)
```
###### Description
Middleware that returns all the IoTA information stored in the module.
##### iotagentLib.middlewares.setIotaInformation()
###### Signature
```javascript
function setIotaInformation(newIoTAInfo)
```
###### Description
Stores the information about the IoTAgent for further use in the `retrieveVersion()` middleware.
###### Params
- _newIoTAInfo_: Object containing all the IoTA Information.
## DB Models (from API document)
> **WARNING** This section is outdated. DB fields described here may be outdated and not reflect the current
> implementation of the IoT Agent Library.
The following sections describe the models used in the database to store the information about the devices and the
config groups.
### Config group model
The table below shows the information held in the Config group provisioning resource and the correspondence between the
API resource fields and the same fields in the database model.
You can find the description of the fields in the config group datamodel of the
[API document](../api.md#config-group-datamodel).
| Payload Field | DB Field | Note |
| ------------------------------ | ------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------ |
| `service` | `service` | |
| `subservice` | `subservice` | |
| `resource` | `resource` | |
| `apikey` | `apikey` | |
| `timestamp` | `timestamp` | |
| `entity_type` | `entity_type` | |
| `trust` | `trust` | |
| `cbHost` | `cbHost` | |
| `lazy` | `lazy` | |
| `commands` | `commands` | |
| `attributes` | `attributes` | |
| `static_attributes` | `staticAttributes` | |
| `internal_attributes` | `internalAttributes` | |
| `explicitAttrs` | `explicitAttrs` | |
| `entityNameExp` | `entityNameExp` | |
| `ngsiVersion` | `ngsiVersion` | |
| `defaultEntityNameConjunction` | `defaultEntityNameConjunction` | optional string value to set default conjunction string used to compose a default `entity_name` when is not provided at device provisioning time. |
| `autoprovision` | `autoprovision` | |
### Device model
The table below shows the information held in the Device resource. The table also contains the correspondence between
the API resource fields and the same fields in the database model.
You can find the description of the fields in the config group datamodel of the
[API document](../api.md#device-datamodel).
| Payload Field | DB Field | Note |
| --------------------- | -------------------- | :----------------------------------------------------------------------------------------------------------------------------------- |
| `device_id` | `id` | |
| `service` | `service` | |
| `service_path` | `subservice` | |
| `entity_name` | `name` | |
| `entity_type` | `type` | |
| `timezone` | `timezone` | |
| `timestamp` | `timestamp` | |
| `apikey` | `apikey` | |
| `endpoint` | `endpoint` | |
| `protocol` | `protocol` | Name of the device protocol, for its use with an IoT Manager. IE: IoTA-UL |
| `transport` | `transport` | |
| `attributes` | `active` | |
| `lazy` | `lazy` | |
| `commands` | `commands` | |
| `internal_attributes` | `internalAttributes` | List of internal attributes with free format for specific IoT Agent configuration. I.E:LWM2M mappings from object URIs to attributes |
| `static_attributes` | `staticAttributes` | |
| `explicitAttrs` | `explicitAttrs` | |
| `ngsiVersion` | `ngsiVersion` | |
## Developing a new IoT Agent
> **WARNING** This section is outdated. Methods and steps described here may be outdated and not reflect the current
> implementation of the IoT Agent Library. You could have a look to other IoT Agents developed using the IoT Agent
> Library to get a better idea of how to use it, like the
> [IoT Agent JSON](http://www.github.com/telefonicaid/iotagent-json)
This section's goal is to show how to develop a new IoT Agent step by step. To do so, a simple invented HTTP protocol
will be used, so it can be tested with simple command-line instructions as `curl` and `nc`.
### Protocol
The invented protocol will be freely adapted from
[Ultralight 2.0](https://github.com/telefonicaid/fiware-IoTAgent-Cplusplus/blob/develop/doc/modules.md#ultra-light-agent).
Whenever a device wants to send an update, it will send a request as the following:
```bash
curl -X GET 'http://127.0.0.1:8080/iot/d?i=ULSensor&k=abc&d=t|15,l|19.6' -i
```
Where:
- **i**: is the device ID.
- **k**: the API Key for the device's service.
- **d**: the data payload, consisting of key-value pairs separated by a pipe (`|`), with each pair separated by comma
(`,`);
### Requirements
This tutorial expects a Node.js v8 (at least) installed and working on your machine. It also expects you to have access
to a Context Broker (without any security proxies).
### Basic IoT Agent
In this first chapter, we will just develop an IoT Agent with a fully connected North Port. This will send and receive
NGSI traffic and can be administered using the IoT Agent's Device Provisioning API. The South Port will remain
unconnected and no native protocol traffic will be sent to the devices. This may seem useless (and indeed it is) but it
will serve us well on showing the basic steps in the creation of an IoT Agent.
First of all, we have to create the Node project. Create a folder to hold your project and type the following
instruction:
```bash
npm init
```
This will create the `package.json` file for our project. Now, add the following lines to your project file:
```json
"dependencies": {
"iotagent-node-lib": "*"
},
```
And install the dependencies, executing, as usual:
```bash
npm install
```
The first step is to write a configuration file, that will be used to tune the behavior of our IOTA. The contents can be
copied from the following example:
```javascript
var config = {
logLevel: 'DEBUG',
contextBroker: {
host: 'localhost',
port: '1026'
},
server: {
port: 4041
},
deviceRegistry: {
type: 'memory'
},
types: {},
service: 'howtoService',
subservice: '/howto',
providerUrl: 'http://localhost:4041',
defaultType: 'Thing'
};
module.exports = config;
```
Create a `config.js` file with it in the root folder of your project. Remember to change the Context Broker IP to your
local Context Broker.
Now we can begin with the code of our IoT Agent. The very minimum code we need to start an IoT Agent is the following:
```javascript
var iotAgentLib = require('iotagent-node-lib'),
config = require('./config');
iotAgentLib.activate(config, function (error) {
if (error) {
console.log('There was an error activating the IOTA');
process.exit(1);
}
});
```
The IoT Agent is now ready to be used. Execute it with the following command:
```bash
node index.js
```
The North Port interface should now be fully functional, i.e.: management of device registrations and config groups.
### IoT Agent With Active attributes
In the previous section we created an IoT Agent that