Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions CHANGES_NEXT_RELEASE
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ Refresh Documentation
Add NGSIv2 metadata support to device provisioned attributes
Fix: Error message when sending measures with unknown/undefined attribute
Add Null check within executeWithSecurity() to avoid crash (#829)
NGSI-LD Command support (#848)
Basic NGSI-LD active measures support (#841)
Add GeoJSON and DateTime, unitCode and observedAt NGSI-LD support (#843)
- The NGSI v2 `TimeInstant` element has been mapped onto the NGSI-LD `observedAt` property
Expand Down
6 changes: 6 additions & 0 deletions doc/installationguide.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,10 @@ used for the same purpose. For instance:
the IoTAgent runs in a single thread. For more details about multi-core functionality, please refer to the
[Cluster](https://nodejs.org/api/cluster.html) module in Node.js and
[this section](howto.md#iot-agent-in-multi-thread-mode) of the library documentation.
- **fallbackTenant** - For Linked Data Context Brokers which do not support multi-tenancy, this provides an alternative mechanism for suppling the `NGSILD-Tenant` header.
Note that for backwards compatibility with NGSI v2, the `fiware-service` header is already used as alternative if the `NGSILD-Tenant` header is not supplied.
- **fallbackPath** - For Linked Data Context Brokers which do not support a service path, this provides an alternative mechanism for suppling the `NGSILD-Path` header.
Note that for backwards compatibility with NGSI v2, the `fiware-service-path` header is already used as alternative if the `NGSILD-Path` header is not supplied.

### Configuration using environment variables

Expand Down Expand Up @@ -282,3 +286,5 @@ overrides.
| IOTA_AUTOCAST | `autocast` |
| IOTA_MULTI_CORE | `multiCore` |
| IOTA_JSON_LD_CONTEXT | `jsonLdContext` |
| IOTA_FALLBACK_TENANT | `fallbackTenant` |
| IOTA_FALLBACK_PATH | `fallbackPath` |
9 changes: 8 additions & 1 deletion lib/commonConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,9 @@ function processEnvironmentVariables() {
'IOTA_POLLING_EXPIRATION',
'IOTA_POLLING_DAEMON_FREQ',
'IOTA_MULTI_CORE',
'IOTA_JSON_LD_CONTEXT'
'IOTA_JSON_LD_CONTEXT',
'IOTA_FALLBACK_TENANT',
'IOTA_FALLBACK_PATH'
],
iotamVariables = [
'IOTA_IOTAM_URL',
Expand Down Expand Up @@ -157,6 +159,11 @@ function processEnvironmentVariables() {
config.contextBroker.jsonLdContext = process.env.IOTA_JSON_LD_CONTEXT;
}

config.contextBroker.fallbackTenant = process.env.IOTA_FALLBACK_TENANT ||
config.contextBroker.service || 'iotagent';
config.contextBroker.fallbackPath = process.env.IOTA_FALLBACK_PATH ||
config.contextBroker.subservice || '/';

// North Port Configuration (ensuring the configuration sub-object exists before start using it)
if (config.server === undefined) {
config.server = {};
Expand Down
2 changes: 2 additions & 0 deletions lib/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ module.exports = {
TIMESTAMP_TYPE_NGSI2: 'DateTime',
SERVICE_HEADER: 'fiware-service',
SUBSERVICE_HEADER: 'fiware-servicepath',
NGSI_LD_TENANT_HEADER: 'NGSILD-Tenant',
NGSI_LD_PATH_HEADER: 'NGSILD-Path',
//FIXME: check Keystone support this in lowercase, then change
AUTH_HEADER: 'X-Auth-Token',

Expand Down
5 changes: 5 additions & 0 deletions lib/fiware-iotagent-lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ var async = require('async'),
intoTrans = require('./services/common/domain').intoTrans,
middlewares = require('./services/common/genericMiddleware'),
db = require('./model/dbConn'),
ngsiService = require('./services/ngsi/ngsiService'),
subscriptions = require('./services/ngsi/subscriptionService'),
statsRegistry = require('./services/stats/statsRegistry'),
domainUtils = require('./services/common/domain'),
Expand Down Expand Up @@ -164,6 +165,10 @@ function doActivate(newConfig, callback) {
config.setRegistry(registry);
config.setGroupRegistry(groupRegistry);
config.setCommandRegistry(commandRegistry);
deviceService.init();
subscriptions.init();
contextServer.init();
ngsiService.init();

commands.start();

Expand Down
37 changes: 19 additions & 18 deletions lib/services/devices/deviceService.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,22 @@ var async = require('async'),
_ = require('underscore'),
context = {
op: 'IoTAgentNGSI.DeviceService'
},
NGSIv1 = require('./devices-NGSI-v1'),
NGSIv2 = require('./devices-NGSI-v2'),
NGSILD = require('./devices-NGSI-LD');
};

let deviceHandler;

/**
* Loads the correct device handler based on the current config.
*/
function init(){
if (config.checkNgsiLD()) {
deviceHandler = require('./devices-NGSI-LD');
} else if (config.checkNgsi2()) {
deviceHandler = require('./devices-NGSI-v2');
} else {
deviceHandler = require('./devices-NGSI-v1');
}
}

/**
* Creates the initial entity representing the device in the Context Broker. This is important mainly to allow the
Expand All @@ -51,13 +63,7 @@ var async = require('async'),
* @param {Object} newDevice Device object that will be stored in the database.
*/
function createInitialEntity(deviceData, newDevice, callback) {
if (config.checkNgsiLD()) {
NGSILD.createInitialEntity(deviceData, newDevice, callback);
} else if (config.checkNgsi2()) {
NGSIv2.createInitialEntity(deviceData, newDevice, callback);
} else {
NGSIv1.createInitialEntity(deviceData, newDevice, callback);
}
deviceHandler.createInitialEntity(deviceData, newDevice, callback);
}

/**
Expand Down Expand Up @@ -348,13 +354,7 @@ function unregisterDevice(id, service, subservice, callback) {
}

function updateRegisterDevice(deviceObj, callback) {
if (config.checkNgsiLD()) {
NGSILD.updateRegisterDevice(deviceObj, callback);
} else if (config.checkNgsi2()) {
NGSIv2.updateRegisterDevice(deviceObj, callback);
} else {
NGSIv1.updateRegisterDevice(deviceObj, callback);
}
deviceHandler.updateRegisterDevice(deviceObj, callback);
}

/**
Expand Down Expand Up @@ -553,3 +553,4 @@ exports.clearRegistry = intoTrans(context, checkRegistry)(clearRegistry);
exports.retrieveDevice = intoTrans(context, checkRegistry)(retrieveDevice);
exports.mergeDeviceWithConfiguration = mergeDeviceWithConfiguration;
exports.findConfigurationGroup = findConfigurationGroup;
exports.init = init;
23 changes: 10 additions & 13 deletions lib/services/devices/devices-NGSI-LD.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ function createInitialEntityHandlerNgsiLD(deviceData, newDevice, callback) {
alarms.raise(constants.ORION_ALARM, error);

callback(error);
} else if (response && response.statusCode === 200) {
} else if (response && response.statusCode === 204 ) {
alarms.release(constants.ORION_ALARM);
logger.debug(context, 'Initial entity created successfully.');
callback(null, newDevice);
Expand Down Expand Up @@ -120,7 +120,7 @@ function updateEntityHandlerNgsiLD(deviceData, updatedDevice, callback) {
alarms.raise(constants.ORION_ALARM, error);

callback(error);
} else if (response && response.statusCode === 200) {
} else if (response && response.statusCode === 204) {
alarms.release(constants.ORION_ALARM);
logger.debug(context, 'Entity updated successfully.');
callback(null, updatedDevice);
Expand Down Expand Up @@ -170,19 +170,17 @@ function createInitialEntityNgsiLD(deviceData, newDevice, callback) {
}

json = ngsiLD.formatAsNGSILD(json);
delete json['@context'];

var options = {
url: config.getConfig().contextBroker.url + '/ngsi-ld/v1/entityOperations/upsert/',
method: 'POST',
json: [json],
headers: {
'fiware-service': deviceData.service,
'Content-Type': 'application/ld+json',
Link:
'<' +
config.getConfig().contextBroker.jsonLdContext +
'>; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json"'
'fiware-servicepath': deviceData.subservice,
'NGSILD-Tenant': deviceData.service,
'NGSILD-Path': deviceData.subservice,
'Content-Type': 'application/ld+json'
}
};

Expand Down Expand Up @@ -212,11 +210,10 @@ function updateEntityNgsiLD(deviceData, updatedDevice, callback) {
json: {},
headers: {
'fiware-service': deviceData.service,
'Content-Type': 'application/ld+json',
Link:
'<' +
config.getConfig().contextBroker.jsonLdContext +
'>; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json"'
'fiware-servicepath': deviceData.subservice,
'NGSILD-Tenant': deviceData.service,
'NGSILD-Path': deviceData.subservice,
'Content-Type': 'application/ld+json'
}
};

Expand Down
18 changes: 7 additions & 11 deletions lib/services/devices/registrationUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,9 @@ function sendUnregistrationsNgsiLD(deviceData, callback) {
json: true,
headers: {
'fiware-service': deviceData.service,
'fiware-servicepath': deviceData.subservice
'fiware-servicepath': deviceData.subservice,
'NGSILD-Tenant': deviceData.service,
'NGSILD-Path': deviceData.subservice,
}
};
if (deviceData.cbHost && deviceData.cbHost.indexOf('://') !== -1) {
Expand Down Expand Up @@ -441,21 +443,17 @@ function sendRegistrationsNgsiLD(unregister, deviceData, callback) {
}

var properties = [];
var additionalContext = {
'ngsi-ld': 'https://uri.etsi.org/ngsi-ld/default-context/'
};
var lazy = deviceData.lazy || [];
var commands = deviceData.commands || [];

lazy.forEach((element) => {
properties.push(element.name);
additionalContext[element.name] = 'ngsi-ld:' + element.name;
});
commands.forEach((element) => {
properties.push(element.name);
additionalContext[element.name] = 'ngsi-ld:' + element.name;
});


if (properties.length === 0) {
logger.debug(
context,
Expand All @@ -472,10 +470,6 @@ function sendRegistrationsNgsiLD(unregister, deviceData, callback) {
cbHost = 'http://' + deviceData.cbHost;
}

var contexts = [additionalContext];
if (config.getConfig().contextBroker.jsonLdContext) {
contexts.push(config.getConfig().contextBroker.jsonLdContext);
}

var id = String(deviceData.name);
id = id.startsWith(NGSI_LD_URN) ? id : NGSI_LD_URN + deviceData.type + ':' + id;
Expand All @@ -492,11 +486,13 @@ function sendRegistrationsNgsiLD(unregister, deviceData, callback) {
}
],
endpoint: config.getConfig().providerUrl,
'@context': contexts
'@context': config.getConfig().contextBroker.jsonLdContext
},
headers: {
'fiware-service': deviceData.service,
'fiware-servicepath': deviceData.subservice,
'NGSILD-Tenant': deviceData.service,
'NGSILD-Path': deviceData.subservice,
'Content-Type': 'application/ld+json'
}
};
Expand Down
52 changes: 48 additions & 4 deletions lib/services/ngsi/entities-NGSI-LD.js
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,8 @@ function formatAsNGSILD(json) {
*/
function generateNGSILDOperationHandler(operationName, entityName, typeInformation, token, options, callback) {
return function(error, response, body) {
var bodyAsString = body ? JSON.stringify(body, null, 4) : '';

if (error) {
logger.error(context, 'Error found executing ' + operationName + ' action in Context Broker: %s', error);

Expand All @@ -278,15 +280,16 @@ function generateNGSILDOperationHandler(operationName, entityName, typeInformati
);

callback(new errors.BadRequest(body.orionError.details));
} else if (response && operationName === 'update' && response.statusCode === 200) {
} else if (response && operationName === 'update' &&
(response.statusCode === 200 ||response.statusCode === 204)) {
logger.debug(context, 'Received the following response from the CB: Value updated successfully\n');
alarms.release(constants.ORION_ALARM);
callback(null, body);
} else if (response && operationName === 'query' && body !== undefined && response.statusCode === 200) {
logger.debug(
context,
'Received the following response from the CB:\n\n%s\n\n',
JSON.stringify(body, null, 4)
bodyAsString
);
logger.debug(context, 'Value queried successfully');
alarms.release(constants.ORION_ALARM);
Expand All @@ -295,7 +298,7 @@ function generateNGSILDOperationHandler(operationName, entityName, typeInformati
logger.debug(
context,
'Received the following response from the CB:\n\n%s\n\n',
JSON.stringify(body, null, 4)
bodyAsString
);

logger.error(
Expand All @@ -319,7 +322,7 @@ function generateNGSILDOperationHandler(operationName, entityName, typeInformati
logger.debug(
context,
'Received the following response from the CB:\n\n%s\n\n',
JSON.stringify(body, null, 4)
bodyAsString
);

logger.error(context, 'Operation ' + operationName + ' error connecting to the Context Broker: %j', body);
Expand All @@ -344,6 +347,46 @@ function generateNGSILDOperationHandler(operationName, entityName, typeInformati
};
}

/**
* Makes a query to the Device's entity in the context broker using NGSI-LD, with the list
* of attributes given by the 'attributes' array.
*
* @param {String} entityName Name of the entity to query.
* @param {Array} attributes Attribute array containing the names of the attributes to query.
* @param {Object} typeInformation Configuration information for the device.
* @param {String} token User token to identify against the PEP Proxies (optional).
*/
function sendQueryValueNgsiLD(entityName, attributes, typeInformation, token, callback) {
var url = '/ngsi-ld/v1/entities/urn:ngsi-ld:' + typeInformation.type + ':' + entityName;

if (attributes && attributes.length > 0) {
url = url + '?attrs=' + attributes.join(',');
}

var options = NGSIUtils.createRequestObject(url, typeInformation, token);
options.method = 'GET';
options.json = true;

if (!typeInformation || !typeInformation.type) {
callback(new errors.TypeNotFound(null, entityName));
return;
}

logger.debug(context, 'Querying values of the device in the Context Broker at [%s]', options.url);
logger.debug(context, 'Using the following request:\n\n%s\n\n', JSON.stringify(options, null, 4));

request(
options,
generateNGSILDOperationHandler('query', entityName, typeInformation, token, options, function(error, result) {
if (error) {
callback(error);
} else {
NGSIUtils.applyMiddlewares(NGSIUtils.queryMiddleware, result, typeInformation, callback);
}
})
);
}

/**
* 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-LD's attribute format.
Expand Down Expand Up @@ -505,3 +548,4 @@ function sendUpdateValueNgsiLD(entityName, attributes, typeInformation, token, c

exports.formatAsNGSILD = formatAsNGSILD;
exports.sendUpdateValue = sendUpdateValueNgsiLD;
exports.sendQueryValue = sendQueryValueNgsiLD;
Loading