Skip to content

Commit

Permalink
Merge pull request #68 from telefonicaid/develop
Browse files Browse the repository at this point in the history
New release 0.3.0
  • Loading branch information
dmoranj committed Apr 10, 2015
2 parents 9c217cf + 3ef82dc commit b00a739
Show file tree
Hide file tree
Showing 44 changed files with 3,645 additions and 250 deletions.
17 changes: 11 additions & 6 deletions CHANGES_NEXT_RELEASE
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
- Complete the Provisioning API with CRUD Operations.
- Change signature of unregister() funciton to remove unneeded type.
- Support XML in Context Provider updates and queries.
- Fix multiple errors found during preparation of CPBR8 Workshop.
- Improve the documentation to add: Configuration, Security, and IoT Library testing sections.
- Fix package.json information to prepare the package for publishing.
- ADD Keywords to the package.json.
- ADD Configuration API for dynamically creating configuration groups.
- ADD Device Provisioning API and Device Configuration API commands in the testing clients.
- ADD Pagination in the Device List operations.
- FIX Remove mandatory constraint for service, servicepath and commands in Device Provisioning (#46).
- FIX List devices based on the service and servicepath (#45).
- FIX Lazy attributes mandatory in Device Provisioning (#51).
- FIX Should allow to provision devices with unconfigured type (#50)
- ADD Handler for configuration changes from the Configuration API.
- ADD Constraint to forbid multiple devices with the same ID (#48).
- ADD Constraint to ensure uniqueness of device configurations (#53).
226 changes: 199 additions & 27 deletions README.md

Large diffs are not rendered by default.

234 changes: 222 additions & 12 deletions bin/iotAgentTester.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ var config = require('../config'),
service: 'tester',
subservice: '/test'
},
configIot = {
host: 'localhost',
port: 4041,
name: 'default',
service: 'tester',
subservice: '/test'
},
separator = '\n\n\t';

function queryContext(commands) {
Expand Down Expand Up @@ -177,6 +184,27 @@ function configure(commands) {
config.subservice = commands[3];
}

function showConfig(commands) {
console.log('\nCurrent configuration:\n\n');
console.log(JSON.stringify(config, null, 4));
console.log('\n');
clUtils.prompt();
}

function configureIot(commands) {
configIot.host = commands[0];
configIot.port = commands[1];
config.service = commands[2];
config.subservice = commands[3];
}

function showConfigIot(commands) {
console.log('\nCurrent configuration:\n\n');
console.log(JSON.stringify(configIot, null, 4));
console.log('\n');
clUtils.prompt();
}

function discoverContext(commands) {
var options = {
url: 'http://' + config.host + ':' + config.port + '/v1/registry/discoverContextAvailability',
Expand Down Expand Up @@ -212,7 +240,7 @@ function discoverContext(commands) {
function provisionDevice(commands) {
function generateOptions(deviceConfig, callback) {
var options = {
uri: 'http://' + commands[0] + ':' + commands[1] + '/iot/devices',
uri: 'http://' + configIot.host + ':' + configIot.port + '/iot/devices',
method: 'POST'
};

Expand Down Expand Up @@ -246,7 +274,7 @@ function provisionDevice(commands) {
clUtils.prompt();
}

fs.readFile(commands[2], 'utf8', function (error, deviceConfig) {
fs.readFile(commands[0], 'utf8', function (error, deviceConfig) {
if (error && error.code === 'ENOENT') {
console.error('File not found');
clUtils.prompt();
Expand All @@ -259,11 +287,157 @@ function provisionDevice(commands) {
});
}

function showConfig(commands) {
console.log('\nCurrent configuration:\n\n');
console.log(JSON.stringify(config, null, 4));
console.log('\n');
clUtils.prompt();
function listProvisioned(commands) {
var options = {
uri: 'http://' + configIot.host + ':' + configIot.port + '/iot/devices',
method: 'GET'
};

console.log('Devices provisioned in host [%s:%s]', configIot.host, configIot.port);
console.log('----------------------------------------------------------------');

request(options, function(error, result, body) {
if (error) {
console.log('Couldn\'t connect with the provisioning server: ' + error.toString());
} else if (result.statusCode === 200 && body) {
var parsedBody = JSON.parse(body);
console.log(JSON.stringify(parsedBody, null, 4));
} else {
console.log('Unexpected application error. Status: ' + result.statusCode);
}
clUtils.prompt();
});
}

function removeProvisioned(commands) {
var options = {
uri: 'http://' + configIot.host + ':' + configIot.port + '/iot/devices/' + commands[0],
method: 'DELETE'
};

console.log('Removing device [%s] [%s:%s]', commands[0], configIot.host, configIot.port);
console.log('----------------------------------------------------------------');

request(options, function(error, result, body) {
if (error) {
console.log('Couldn\'t connect with the provisioning server: ' + error.toString());
} else if (result.statusCode === 200 && body) {
var parsedBody = JSON.parse(body);
console.log('Device [%s] removed successfully', commands[0]);
} else {
console.log('Unexpected application error. Status: ' + result.statusCode);
}
clUtils.prompt();
});
}

function addGroup(commands) {
console.log('Adding device groups to host [%s:%s] from file [%s]', configIot.host, configIot.port, commands[0]);

function generateOptions(deviceConfig, callback) {
var options = {
uri: 'http://' + configIot.host + ':' + configIot.port + '/iot/agents/' + configIot.name + '/services',
method: 'POST',
headers: {
'fiware-service': configIot.service,
'fiware-servicepath': configIot.subservice
}
};

try {
var payload = JSON.parse(deviceConfig);
options.json = payload;
callback(null, options);
} catch (e) {
callback('Wrong JSON. Couldn\'t parse');
}
}

function sendProvisionRequest(options, callback) {
request(options, function(error, result, body) {
if (error) {
callback('Couldn\'t connect with the provisioning server: ' + error.toString());
} else if (result.statusCode === 200 && body) {
callback(null, 'Device group successfully provisioned');
} else {
callback('Unexpected application error. Status: ' + result.statusCode);
}
});
}

function handleOut(error, msg) {
if (error) {
console.error(error);
} else {
console.log(msg);
}
clUtils.prompt();
}

fs.readFile(commands[0], 'utf8', function (error, deviceConfig) {
if (error && error.code === 'ENOENT') {
console.error('File not found');
clUtils.prompt();
} else {
async.waterfall([
async.apply(generateOptions, deviceConfig),
sendProvisionRequest
], handleOut);
}
});
}

function removeGroup(commands) {
var options = {
uri: 'http://' + configIot.host + ':' + configIot.port + '/iot/agents/' + configIot.name + '/services',
method: 'DELETE',
headers: {
'fiware-service': configIot.service,
'fiware-servicepath': configIot.subservice
}
};

console.log('Removing device group for subservice [%s] from [%s:%s]',
configIot.subservice, configIot.host, configIot.port);

console.log('----------------------------------------------------------------');

request(options, function(error, result, body) {
if (error) {
console.log('Couldn\'t connect with the provisioning server: ' + error.toString());
} else if (result.statusCode === 200 && body) {
console.log('Device group for subservice [%s] removed successfully', configIot.subservice);
} else {
console.log('Unexpected application error. Status: ' + result.statusCode);
}
clUtils.prompt();
});
}

function listGroups(commands) {
console.log('Devices groups provisioned in host [%s:%s]', configIot.host, configIot.port);
console.log('----------------------------------------------------------------');
var options = {
uri: 'http://' + configIot.host + ':' + configIot.port + '/iot/agents/' + configIot.name + '/services',
method: 'GET',
headers: {
'fiware-service': configIot.service,
'fiware-servicepath': '/*'
}
};

request(options, function(error, result, body) {
console.log(JSON.stringify(result.headers));
if (error) {
console.log('Couldn\'t connect with the provisioning server: ' + error.toString());
} else if (result.statusCode === 200 && body) {
var parsedBody = JSON.parse(body);
console.log(JSON.stringify(parsedBody, null, 4));
} else {
console.log('Unexpected application error. Status: ' + result.statusCode);
}
clUtils.prompt();
});
}

var commands = {
Expand Down Expand Up @@ -294,21 +468,57 @@ var commands = {
description: '\tGet all the context providers for a entity and type.',
handler: discoverContext
},
'config': {
'configCb': {
parameters: ['host', 'port', 'service', 'subservice'],
description: '\tConfig a new host and port for the remote Context Broker.',
handler: configure
},
'showConfig': {
'showConfigCb': {
parameters: [],
description: '\tShow the current configuration of the client.',
description: '\tShow the current configuration of the client for the Context Broker.',
handler: showConfig
},
'configIot': {
parameters: ['host', 'port', 'service', 'subservice'],
description: '\tConfig a new host and port for the remote IoT Agent.',
handler: configureIot
},
'showConfigIot': {
parameters: [],
description: '\tShow the current configuration of the client for the IoT Agent.',
handler: showConfigIot
},
'provision': {
parameters: ['host', 'port', 'filename'],
parameters: ['filename'],
description: '\tProvision a new device using the Device Provisioning API. The device configuration is \n' +
'\tread from the script location.',
'\tread from the file specified in the "filename" parameter.',
handler: provisionDevice
},
'listProvisioned': {
parameters: [],
description: '\tList all the provisioned devices in an IoT Agent.',
handler: listProvisioned
},
'removeProvisioned': {
parameters: ['deviceId'],
description: '\tRemove the selected provisioned device from the IoT Agent, specified by its Device ID.',
handler: removeProvisioned
},
'addGroup': {
parameters: ['filename'],
description: '\tAdd a new device group to the specified IoT Agent through the Configuration API. The \n' +
'\tbody is taken from the file specified in the "filename" parameter.',
handler: addGroup
},
'listGroups': {
parameters: [],
description: '\tList all the device groups created in the selected IoT Agent for the configured service',
handler: listGroups
},
'removeGroup': {
parameters: [],
description: '\tRemove the device group corresponding to the current configured subservice.',
handler: removeGroup
}
};

Expand Down
3 changes: 2 additions & 1 deletion config.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ var config = {
service: 'smartGondor',
subservice: '/gardens',
providerUrl: 'http://192.168.56.1:4041',
deviceRegistrationDuration: 'P1M'
deviceRegistrationDuration: 'P1M',
defaultType: 'Thing'
};

module.exports = config;
29 changes: 29 additions & 0 deletions examples/deviceGroup.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"services": [
{
"resource": "/deviceTest",
"apikey": "801230BJKL23Y9090DSFL123HJK09H324HV8732",
"type": "Light",
"trust": "8970A9078A803H3BL98PINEQRW8342HBAMS",
"cbHost": "http://unexistentHost:1026",
"commands": [
{
"name": "wheel1",
"type": "Wheel"
}
],
"lazy": [
{
"name": "luminescence",
"type": "Lumens"
}
],
"active": [
{
"name": "status",
"type": "Boolean"
}
]
}
]
}
36 changes: 36 additions & 0 deletions lib/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ module.exports = {
TypeNotFound: function(id, type) {
this.name = 'TYPE_NOT_FOUND';
this.message = 'Type : ' + type + ' not found for device with id: ' + id;
this.code = 500;
},
MissingAttributes: function(msg) {
this.name = 'MISSING_ATTRIBUTES';
Expand All @@ -71,6 +72,16 @@ module.exports = {
this.message = 'No device was found with id:' + id;
this.code = 404;
},
DuplicateDeviceId: function(id) {
this.name = 'DUPLICATE_DEVICE_ID';
this.message = 'A device with the same pair (Service, DeviceId) was found:' + id;
this.code = 400;
},
DuplicateGroup: function(res, key) {
this.name = 'DUPLICATE_GROUP';
this.message = 'A device configuration already exists for resource ' + res + ' and API Key ' + key;
this.code = 400;
},
SecurityInformationMissing: function(type) {
this.name = 'SECURITY_INFORMATION_MISSING';
this.message = 'Some security information was missing for device type:' + type;
Expand All @@ -95,5 +106,30 @@ module.exports = {
TemplateLoadingError: function(error) {
this.name = 'TEMPLATE_LOADING_ERROR';
this.message = 'Some of the XML Templates could not be found or loaded: ' + error.toString();
},
MissingHeaders: function(msg) {
this.name = 'MISSING_HEADERS';
this.message = 'Some headers were missing from the request: ' + msg;
this.code = 400;
},
MismatchedService: function(service, subservice) {
this.name = 'MISMATCHED_SERVICE';
this.message = 'The declared service didn\'t match the stored one in the entity';
this.code = 403;
},
WrongSyntax: function(msg) {
this.name = 'WRONG_SYNTAX';
this.message = 'Wrong syntax in request: ' + msg;
this.code = 400;
},
DeviceGroupNotFound: function(fields, values) {
this.name = 'DEVICE_GROUP_NOT_FOUND';
if (values && fields) {
this.message = 'Couldn\t find device group for fields: ' + fields + ' and values: ' + values;
} else {
this.message = 'Couldn\t find device group';
}
this.code = 400;
}

};
Loading

0 comments on commit b00a739

Please sign in to comment.