iotagent-node-lib
Version:
IoT Agent library to interface with NGSI Context Broker
181 lines (159 loc) • 6.56 kB
JavaScript
/*
* Copyright 2016 Telefonica Investigación y Desarrollo, S.A.U
*
* This file is part of fiware-iotagent-lib
*
* fiware-iotagent-lib is free software: you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* fiware-iotagent-lib is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with fiware-iotagent-lib.
* If not, see http://www.gnu.org/licenses/.
*
* For those usages not covered by the GNU Affero General Public License
* please contact with::daniel.moranjimenez@telefonica.com
*/
const intoTrans = require('../common/domain').intoTrans;
const logger = require('logops');
const async = require('async');
const apply = async.apply;
const config = require('../../commonConfig');
const constants = require('../../constants');
const ngsiService = require('../ngsi/ngsiService');
const deviceService = require('../devices/deviceService');
const pluginUtils = require('../../plugins/pluginUtils');
let daemonId;
const context = {
op: 'IoTAgentNGSI.CommandService'
};
const expressionPlugin = require('../../plugins/expressionPlugin');
function listCommands(service, subservice, deviceId, callback) {
logger.debug(context, 'Listing all commands for device [%s]', deviceId);
config.getCommandRegistry().list(service, subservice, deviceId, callback);
}
function addCommand(service, subservice, deviceId, command, callback) {
logger.debug(context, 'Adding command [%j] to the queue for deviceId [%s]', command, deviceId);
config.getCommandRegistry().add(service, subservice, deviceId, command, callback);
}
function addCommandDevice(service, subservice, device, command, callback) {
logger.debug(context, 'Adding command [%j] to the queue for device [%j]', command, device);
let deviceCmd;
if (device && device.commands) {
deviceCmd = device.commands.find((c) => c.name === command.name);
}
if (deviceCmd && deviceCmd.expression) {
let parser = expressionPlugin;
// The context for the JEXL expression should be the ID, TYPE, S, SS
let attrList = pluginUtils.getIdTypeServSubServiceFromDevice(device);
attrList = device.staticAttributes ? attrList.concat(device.staticAttributes) : attrList.concat([]);
let ctxt = parser.extractContext(attrList);
logger.debug(context, 'attrList [%j] for device %j', attrList, device);
// expression result will be the full command payload
let cmdValueRes = null;
try {
cmdValueRes = parser.applyExpression(deviceCmd.expression, ctxt, device);
} catch (e) {
// nothing to do
}
command.value = cmdValueRes ? cmdValueRes : deviceCmd.expression;
}
config.getCommandRegistry().add(service, subservice, device.id, command, callback);
}
function updateCommand(service, subservice, deviceId, name, value, callback) {
logger.debug(context, 'Updating command [%s] for deviceId [%s] with value [%s]', name, deviceId, value);
config.getCommandRegistry().update(service, subservice, deviceId, value, callback);
}
function removeCommand(service, subservice, deviceId, name, callback) {
logger.debug(context, 'Removing command [%s] from deviceId [%s]', name, deviceId);
config.getCommandRegistry().remove(service, subservice, deviceId, name, callback);
}
function markAsExpired(command) {
logger.debug('Marking command as expired: %j', command);
function getGroup(device, callback) {
deviceService.findConfigurationGroup(device, function (error, group) {
callback(error, device, group);
});
}
function calculateTypeInformation(device, group, callback) {
deviceService.mergeDeviceWithConfiguration(
['lazy', 'active', 'staticAttributes', 'commands', 'subscriptions'],
[null, null, [], [], [], [], []],
device,
group,
function (error, typeInformation) {
callback(error, device, group, typeInformation);
}
);
}
function updateExpiredCommand(device, group, typeInformation, callback) {
ngsiService.setCommandResult(
device.name,
group.resource,
group.apikey,
command.name,
constants.COMMAND_EXPIRED_MESSAGE,
constants.COMMAND_STATUS_ERROR,
typeInformation,
callback
);
}
async.waterfall(
[
apply(deviceService.getDevice, command.deviceId, null, command.service, command.subservice),
getGroup,
calculateTypeInformation,
updateExpiredCommand
],
function (error) {
if (error) {
logger.error(context, 'Error updating polling command to expire: %j', error);
} else {
logger.debug(context, 'Command successfully expired');
}
}
);
}
function expirationDaemon() {
if (config.getConfig().pollingExpiration) {
config
.getCommandRegistry()
.removeFromDate(Date.now() - config.getConfig().pollingExpiration, function (error, results) {
logger.debug(context, 'Executed expiration daemon');
if (error) {
logger.error(context, 'Error executing expiration daemon: %s', error);
} else if (results && results.length) {
results.map(markAsExpired);
}
});
}
}
function startExpirationDaemon(callback) {
if (config.getConfig().pollingDaemonFrequency) {
daemonId = setInterval(expirationDaemon, config.getConfig().pollingDaemonFrequency);
if (callback) {
callback();
}
}
}
function stopExpirationDaemon(callback) {
if (daemonId) {
clearInterval(daemonId);
}
if (callback) {
callback();
}
}
exports.list = intoTrans(context, listCommands);
exports.add = addCommand;
exports.addCmd = addCommandDevice;
exports.update = updateCommand;
exports.remove = removeCommand;
exports.start = startExpirationDaemon;
exports.stop = stopExpirationDaemon;