iotagent-node-lib 4.6.0 → 4.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/.github/workflows/ci.yml +2 -3
  2. package/CHANGES_NEXT_RELEASE +1 -0
  3. package/Changelog +20 -0
  4. package/config.js +3 -1
  5. package/doc/README.md +1 -0
  6. package/doc/admin.md +39 -5
  7. package/doc/api.md +74 -9
  8. package/doc/devel/northboundinteractions.md +122 -15
  9. package/doc/models/models.md +260 -0
  10. package/doc/requirements.txt +1 -1
  11. package/docker/Mosquitto/Dockerfile +1 -1
  12. package/lib/commonConfig.js +21 -2
  13. package/lib/fiware-iotagent-lib.js +15 -11
  14. package/lib/jexlTranformsMap.js +182 -35
  15. package/lib/model/Command.js +11 -2
  16. package/lib/model/Device.js +8 -3
  17. package/lib/model/Group.js +5 -3
  18. package/lib/model/dbConn.js +53 -112
  19. package/lib/services/commands/commandRegistryMongoDB.js +130 -76
  20. package/lib/services/commands/commandService.js +3 -3
  21. package/lib/services/common/iotManagerService.js +3 -1
  22. package/lib/services/devices/deviceRegistryMemory.js +36 -0
  23. package/lib/services/devices/deviceRegistryMongoDB.js +161 -88
  24. package/lib/services/devices/deviceService.js +44 -5
  25. package/lib/services/devices/devices-NGSI-v2.js +6 -1
  26. package/lib/services/groups/groupRegistryMongoDB.js +120 -83
  27. package/lib/services/ngsi/entities-NGSI-v2.js +14 -1
  28. package/lib/services/ngsi/ngsiService.js +32 -1
  29. package/lib/services/northBound/contextServer-NGSI-v2.js +12 -3
  30. package/lib/services/northBound/contextServer.js +2 -1
  31. package/lib/services/northBound/deviceProvisioningServer.js +12 -3
  32. package/lib/services/northBound/northboundServer.js +1 -0
  33. package/lib/templates/createDevice.json +4 -0
  34. package/lib/templates/updateDevice.json +16 -0
  35. package/lib/templates/updateDeviceLax.json +12 -0
  36. package/package.json +4 -4
  37. package/test/functional/config-test.js +3 -2
  38. package/test/functional/testUtils.js +15 -4
  39. package/test/unit/examples/groupProvisioningRequests/provisionFullGroup.json +1 -0
  40. package/test/unit/expressions/jexlExpression-test.js +165 -1
  41. package/test/unit/general/config-multi-core-test.js +1 -2
  42. package/test/unit/general/contextBrokerKeystoneSecurityAccess-test.js +5 -4
  43. package/test/unit/general/deviceService-test.js +6 -5
  44. package/test/unit/memoryRegistry/deviceRegistryMemory_test.js +6 -5
  45. package/test/unit/mongodb/mongodb-connectionoptions-test.js +7 -39
  46. package/test/unit/ngsi-ld/expressions/jexlBasedTransformations-test.js +1 -2
  47. package/test/unit/ngsi-ld/general/config-jsonld-contexts-test.js +1 -2
  48. package/test/unit/ngsi-mixed/provisioning/ngsi-versioning-test.js +8 -5
  49. package/test/unit/ngsiv2/expressions/jexlBasedTransformations-test.js +42 -41
  50. package/test/unit/ngsiv2/general/contextBrokerOAuthSecurityAccess-test.js +11 -10
  51. package/test/unit/ngsiv2/general/deviceService-test.js +6 -5
  52. package/test/unit/ngsiv2/general/https-support-test.js +1 -1
  53. package/test/unit/ngsiv2/lazyAndCommands/active-devices-attribute-update-test.js +4 -3
  54. package/test/unit/ngsiv2/lazyAndCommands/command-test.js +6 -5
  55. package/test/unit/ngsiv2/lazyAndCommands/lazy-devices-test.js +17 -16
  56. package/test/unit/ngsiv2/lazyAndCommands/polling-commands-test.js +10 -18
  57. package/test/unit/ngsiv2/ngsiService/active-devices-test.js +21 -20
  58. package/test/unit/ngsiv2/ngsiService/staticAttributes-test.js +8 -7
  59. package/test/unit/ngsiv2/plugins/alias-plugin_test.js +12 -11
  60. package/test/unit/ngsiv2/plugins/custom-plugin_test.js +3 -2
  61. package/test/unit/ngsiv2/plugins/multientity-plugin_test.js +28 -27
  62. package/test/unit/ngsiv2/provisioning/device-group-api-test.js +6 -4
  63. package/test/unit/ngsiv2/provisioning/device-provisioning-api_test.js +12 -11
  64. package/test/unit/ngsiv2/provisioning/device-provisioning-configGroup-api_test.js +11 -10
  65. package/test/unit/ngsiv2/provisioning/device-registration_test.js +5 -4
  66. package/test/unit/ngsiv2/provisioning/listProvisionedDevices-test.js +6 -5
  67. package/test/unit/ngsiv2/provisioning/provisionDeviceMultientity-test.js +1 -1
  68. package/test/unit/ngsiv2/provisioning/removeProvisionedDevice-test.js +5 -4
  69. package/test/unit/ngsiv2/provisioning/updateProvisionedDevices-test.js +8 -7
  70. package/test/unit/ngsiv2/ngsiService/subscriptions-test.js +0 -326
@@ -31,7 +31,6 @@ const config = require('../commonConfig');
31
31
  const constants = require('../constants');
32
32
  const alarms = require('../services/common/alarmManagement');
33
33
  const logger = require('logops');
34
- const async = require('async');
35
34
  const errors = require('../errors');
36
35
  let defaultDb;
37
36
  const DEFAULT_DB_NAME = 'iotagent';
@@ -40,9 +39,9 @@ const context = {
40
39
  };
41
40
 
42
41
  function loadModels() {
43
- require('./Device').load(defaultDb);
44
- require('./Group').load(defaultDb);
45
- require('./Command').load(defaultDb);
42
+ require('./Device').load();
43
+ require('./Group').load();
44
+ require('./Command').load();
46
45
  }
47
46
 
48
47
  /**
@@ -50,93 +49,52 @@ function loadModels() {
50
49
  *
51
50
  * @this Reference to the dbConn module itself.
52
51
  */
52
+
53
53
  function init(host, db, port, options, callback) {
54
- /*jshint camelcase:false, validthis:true */
55
54
  let url;
56
55
  let retries = 0;
57
56
  let lastError;
58
- const maxRetries =
59
- (config.getConfig().mongodb && config.getConfig().mongodb.retries) || constants.DEFAULT_MONGODB_RETRIES;
57
+ const maxRetries = config.getConfig().mongodb?.retries || constants.DEFAULT_MONGODB_RETRIES;
60
58
 
61
59
  function addPort(item) {
62
- return item + ':' + port;
63
- }
64
-
65
- function commaConcat(previous, current, currentIndex) {
66
- if (currentIndex !== 0) {
67
- previous += ',';
68
- }
69
-
70
- previous += current;
71
-
72
- return previous;
60
+ return `${item}:${port}`;
73
61
  }
74
62
 
75
63
  url = 'mongodb://';
76
64
 
77
65
  if (options.auth) {
78
- url += options.auth.user + ':' + options.auth.password + '@';
66
+ url += `${encodeURIComponent(options.auth.user)}:${encodeURIComponent(options.auth.password)}@`;
79
67
  }
80
68
 
81
- const hosts = host.split(',').map(addPort).reduce(commaConcat, '');
82
-
83
- url += hosts + '/' + db;
69
+ const hosts = host.split(',').map(addPort).join(',');
70
+ url += `${hosts}/${db}`;
84
71
 
85
72
  if (options.extraArgs) {
86
- if (options.extraArgs instanceof Object && Object.keys(options.extraArgs).length > 0) {
87
- url += '?';
88
- url += Object.entries(options.extraArgs)
89
- .map(function ([k, v]) {
90
- return encodeURIComponent(k) + '=' + encodeURIComponent(v);
91
- })
92
- .join('&');
73
+ const query = new URLSearchParams(options.extraArgs).toString();
74
+ if (query) {
75
+ url += `?${query}`;
93
76
  }
94
77
  delete options.extraArgs;
95
78
  }
96
79
 
97
- /* eslint-disable-next-line no-unused-vars */
98
- function createConnectionHandler(error, results) {
99
- if (defaultDb) {
100
- logger.info(context, 'Successfully connected to MongoDB.');
101
- module.exports.db = defaultDb;
102
- loadModels();
103
- } else {
104
- logger.error(context, 'MONGODB-002: Error found after [%d] attempts: %s', retries, error || lastError);
105
- }
106
-
107
- callback(error);
108
- }
109
-
110
- function retryCheck() {
111
- return !defaultDb && retries < maxRetries;
112
- }
113
-
114
- function connectionAttempt(url, options, callback) {
115
- logger.info(context, 'Attempting to connect to MongoDB instance with url %j. Attempt %d', url, retries);
116
- // FIXME: useNewUrlParser is no longer used in underlying mongodb driver 4.x
117
- // (see https://github.com/mongodb/node-mongodb-native/blob/HEAD/etc/notes/CHANGES_4.0.0.md)
118
- // but not sure if current mongoose version is still using mongodb 3.x internally
119
- // probably mongodb-connectionoptions-test.js needs to be fixed if useNewUrlParser is removed at the end
120
- options.useNewUrlParser = true;
121
- options.useUnifiedTopology = true;
122
- mongoose.set('useCreateIndex', true);
123
- /* eslint-disable-next-line no-unused-vars */
124
- const candidateDb = mongoose.createConnection(url, options, function (error, result) {
125
- if (error) {
126
- logger.error(context, 'MONGODB-001: Error trying to connect to MongoDB: %s', error);
127
- lastError = error;
128
- } else {
129
- defaultDb = candidateDb;
80
+ function connectionAttempt(callback) {
81
+ logger.info(context, `Attempting to connect to MongoDB at ${url}. Attempt ${retries + 1}`);
130
82
 
83
+ mongoose
84
+ .connect(url, options)
85
+ .then(() => {
86
+ defaultDb = mongoose.connection;
87
+ logger.info(context, 'Successfully connected to MongoDB.');
88
+ loadModels();
131
89
  defaultDb.on('error', function (error) {
132
90
  logger.error(context, 'Mongo Driver error: %j', error);
91
+ lastError = error;
133
92
  alarms.raise(constants.MONGO_ALARM, error);
134
93
  });
135
94
  /* eslint-disable-next-line no-unused-vars */
136
95
  defaultDb.on('connecting', function (error) {
137
96
  logger.debug(context, 'Mongo Driver connecting');
138
97
  });
139
-
140
98
  defaultDb.on('connected', function () {
141
99
  logger.debug(context, 'Mongo Driver connected');
142
100
  });
@@ -159,69 +117,52 @@ function init(host, db, port, options, callback) {
159
117
  defaultDb.on('close', function () {
160
118
  logger.debug(context, 'Mongo Driver close');
161
119
  });
162
- }
163
-
164
- callback();
165
- });
166
- }
167
-
168
- function tryCreateConnection(callback) {
169
- const attempt = async.apply(connectionAttempt, url, options, callback);
170
- const seconds =
171
- (config.getConfig().mongodb && config.getConfig().mongodb.retryTime) ||
172
- constants.DEFAULT_MONGODB_RETRY_TIME;
173
-
174
- retries++;
175
-
176
- if (retries === 1) {
177
- logger.info(context, 'First connection attempt');
178
- attempt();
179
- } else {
180
- logger.info(context, 'Waiting %d seconds before attempting again.', seconds);
181
- setTimeout(attempt, seconds * 1000);
182
- }
120
+ callback();
121
+ })
122
+ .catch((err) => {
123
+ logger.error(context, `MONGODB-001: Error trying to connect to MongoDB: ${err}`);
124
+ lastError = err;
125
+ retries++;
126
+ if (retries < maxRetries) {
127
+ const retryTime = config.getConfig().mongodb?.retryTime || constants.DEFAULT_MONGODB_RETRY_TIME;
128
+ logger.info(context, `Retrying in ${retryTime} seconds...`);
129
+ setTimeout(() => connectionAttempt(callback), retryTime * 1000);
130
+ } else {
131
+ logger.error(
132
+ context,
133
+ 'MONGODB-002: Error to connect found after %d attempts: %s',
134
+ retries,
135
+ lastError
136
+ );
137
+ callback(err);
138
+ }
139
+ });
183
140
  }
184
141
 
185
- defaultDb = null;
186
- async.whilst(retryCheck, tryCreateConnection, createConnectionHandler);
142
+ connectionAttempt(callback);
187
143
  }
188
144
 
189
145
  function configureDb(callback) {
190
- /*jshint camelcase:false, validthis:true */
191
146
  const currentConfig = config.getConfig();
192
-
193
- if (currentConfig.deviceRegistry && currentConfig.deviceRegistry.type === 'mongodb') {
194
- if (!currentConfig.mongodb || !currentConfig.mongodb.host) {
147
+ if (currentConfig.deviceRegistry?.type === 'mongodb') {
148
+ if (!currentConfig.mongodb?.host) {
195
149
  logger.fatal(context, 'MONGODB-003: No host found for MongoDB driver.');
196
150
  callback(new errors.BadConfiguration('No host found for MongoDB driver'));
197
151
  } else {
198
- let dbName = currentConfig.mongodb.db;
152
+ const dbName = currentConfig.mongodb.db || DEFAULT_DB_NAME;
199
153
  const port = currentConfig.mongodb.port || 27017;
200
154
  const options = {};
201
155
 
202
- if (!currentConfig.mongodb.db) {
203
- dbName = DEFAULT_DB_NAME;
204
- }
205
-
206
- if (currentConfig.mongodb.replicaSet) {
207
- options.replicaSet = currentConfig.mongodb.replicaSet;
208
- }
209
-
210
- if (currentConfig.mongodb.ssl) {
211
- options.ssl = currentConfig.mongodb.ssl;
212
- }
213
-
214
- if (currentConfig.mongodb.extraArgs) {
215
- options.extraArgs = currentConfig.mongodb.extraArgs;
216
- }
156
+ if (currentConfig.mongodb.replicaSet) options.replicaSet = currentConfig.mongodb.replicaSet;
157
+ if (currentConfig.mongodb.ssl) options.ssl = currentConfig.mongodb.ssl;
158
+ if (currentConfig.mongodb.extraArgs) options.extraArgs = currentConfig.mongodb.extraArgs;
217
159
 
218
160
  if (currentConfig.mongodb.user && currentConfig.mongodb.password) {
219
- options.auth = {};
220
- options.auth.user = currentConfig.mongodb.user;
221
- options.auth.password = currentConfig.mongodb.password;
222
- // authSource only applies if auth is set
161
+ options.auth = {
162
+ user: currentConfig.mongodb.user,
163
+ password: currentConfig.mongodb.password
164
+ };
223
165
  if (currentConfig.mongodb.authSource) {
224
- // Overload extraArgs if it was set
225
166
  options.extraArgs = {
226
167
  ...options.extraArgs,
227
168
  authSource: currentConfig.mongodb.authSource
@@ -229,7 +170,7 @@ function configureDb(callback) {
229
170
  }
230
171
  }
231
172
 
232
- init(config.getConfig().mongodb.host, dbName, port, options, callback);
173
+ init(currentConfig.mongodb.host, dbName, port, options, callback);
233
174
  }
234
175
  } else {
235
176
  callback();
@@ -22,7 +22,7 @@
22
22
  */
23
23
 
24
24
  const logger = require('logops');
25
- const dbService = require('../../model/dbConn');
25
+ const mongoose = require('mongoose');
26
26
  const intoTrans = require('../common/domain').intoTrans;
27
27
  const errors = require('../../errors');
28
28
  const Command = require('../../model/Command');
@@ -45,24 +45,26 @@ function findCommand(service, subservice, deviceId, name, callback) {
45
45
 
46
46
  query.select({ __v: 0 });
47
47
 
48
- query.exec(function handleGet(error, data) {
49
- if (error) {
48
+ query
49
+ .exec({})
50
+ .then((data) => {
51
+ if (data) {
52
+ callback(null, data);
53
+ } else {
54
+ logger.debug(
55
+ context,
56
+ 'Command for DeviceID [%j] with name [%j] not found with [%j]',
57
+ deviceId,
58
+ name,
59
+ queryObj
60
+ );
61
+ callback(new errors.CommandNotFound(name, queryObj));
62
+ }
63
+ })
64
+ .catch((error) => {
50
65
  logger.debug(context, 'Internal MongoDB Error getting command: %s', error);
51
-
52
66
  callback(new errors.InternalDbError(error));
53
- } else if (data) {
54
- callback(null, data);
55
- } else {
56
- logger.debug(
57
- context,
58
- 'Command for DeviceID [%j] with name [%j] not found with [%j]',
59
- deviceId,
60
- name,
61
- queryObj
62
- );
63
- callback(new errors.CommandNotFound(name, queryObj));
64
- }
65
- });
67
+ });
66
68
  }
67
69
 
68
70
  function updateCommand(service, subservice, deviceId, command, callback) {
@@ -72,9 +74,14 @@ function updateCommand(service, subservice, deviceId, command, callback) {
72
74
  } else {
73
75
  commandDAO.value = command.value;
74
76
 
75
- commandDAO.save(function (error) {
76
- callback(error, commandDAO.toObject());
77
- });
77
+ commandDAO
78
+ .save({})
79
+ .then((commandDAOs) => {
80
+ callback(null, commandDAOs.toObject());
81
+ })
82
+ .catch((error) => {
83
+ callback(error);
84
+ });
78
85
  }
79
86
  });
80
87
  }
@@ -82,7 +89,21 @@ function updateCommand(service, subservice, deviceId, command, callback) {
82
89
  function createCommand(service, subservice, deviceId, command, callback) {
83
90
  /* eslint-disable-next-line new-cap */
84
91
  const commandObj = new Command.model();
85
- const attributeList = ['name', 'type', 'value'];
92
+ const attributeList = [
93
+ 'name',
94
+ 'type',
95
+ 'value',
96
+ // new Command fields
97
+ 'execTs',
98
+ 'status',
99
+ 'info',
100
+ 'onDelivered',
101
+ 'onOk',
102
+ 'onError',
103
+ 'onInfo',
104
+ 'cmdExecution',
105
+ 'dateExpiration'
106
+ ];
86
107
 
87
108
  for (let i = 0; i < attributeList.length; i++) {
88
109
  commandObj[attributeList[i]] = command[attributeList[i]];
@@ -94,15 +115,15 @@ function createCommand(service, subservice, deviceId, command, callback) {
94
115
 
95
116
  logger.debug(context, 'Storing command for deviceId [%s] with name [%s]', deviceId, command.name);
96
117
 
97
- commandObj.save(function saveHandler(error, commandDAO) {
98
- if (error) {
118
+ commandObj
119
+ .save({})
120
+ .then((commandDAO) => {
121
+ callback(null, commandDAO.toObject());
122
+ })
123
+ .catch((error) => {
99
124
  logger.debug(context, 'Error storing command information: %s', error);
100
-
101
125
  callback(new errors.InternalDbError(error));
102
- } else {
103
- callback(null, commandDAO.toObject());
104
- }
105
- });
126
+ });
106
127
  }
107
128
 
108
129
  function addCommand(service, subservice, deviceId, command, callback) {
@@ -129,16 +150,33 @@ function listCommands(service, subservice, deviceId, callback) {
129
150
  condition.deviceId = deviceId;
130
151
 
131
152
  const query = Command.model.find(condition).sort();
132
-
133
- async.series(
134
- [query.exec.bind(query), Command.model.countDocuments.bind(Command.model, condition)],
135
- function (error, results) {
136
- callback(error, {
137
- count: results[1],
138
- commands: results[0].map(toObjectFn)
153
+ const queryCount = Command.model.countDocuments(condition);
154
+ function funcQuery(cb) {
155
+ query
156
+ .exec({})
157
+ .then((res) => {
158
+ cb(null, res);
159
+ })
160
+ .catch((error) => {
161
+ cb(error);
139
162
  });
140
- }
141
- );
163
+ }
164
+ function funcQueryCount(cb) {
165
+ queryCount
166
+ .exec({})
167
+ .then((res) => {
168
+ cb(null, res);
169
+ })
170
+ .catch((error) => {
171
+ cb(error);
172
+ });
173
+ }
174
+ async.series([funcQuery, funcQueryCount], function (error, results) {
175
+ callback(error, {
176
+ count: results[1],
177
+ commands: results[0].map(toObjectFn)
178
+ });
179
+ });
142
180
  }
143
181
 
144
182
  function remove(service, subservice, deviceId, name, callback) {
@@ -155,26 +193,29 @@ function remove(service, subservice, deviceId, name, callback) {
155
193
  if (error) {
156
194
  callback(error);
157
195
  } else {
158
- Command.model.deleteOne({ _id: command._id }, function (error, commandResult) {
159
- if (error) {
196
+ const query = Command.model.deleteOne({ _id: command._id });
197
+ query
198
+ .exec({})
199
+ .then((commandResult) => {
200
+ if (commandResult && commandResult.result && commandResult.result.n === 1) {
201
+ logger.debug(context, 'Command [%s] successfully removed.', name);
202
+
203
+ callback(null, commandResult);
204
+ } else {
205
+ const deviceInfo = {
206
+ service,
207
+ subservice,
208
+ deviceId,
209
+ name
210
+ };
211
+ logger.debug(context, 'Command [%s] not found for removal with %j', name, deviceInfo);
212
+ callback(new errors.CommandNotFound(name, deviceInfo));
213
+ }
214
+ })
215
+ .catch((error) => {
160
216
  logger.debug(context, 'Internal MongoDB Error getting command: %s', error);
161
-
162
217
  callback(new errors.InternalDbError(error));
163
- } else if (commandResult && commandResult.result && commandResult.result.n === 1) {
164
- logger.debug(context, 'Command [%s] successfully removed.', name);
165
-
166
- callback(null, commandResult);
167
- } else {
168
- const deviceInfo = {
169
- service,
170
- subservice,
171
- deviceId,
172
- name
173
- };
174
- logger.debug(context, 'Command [%s] not found for removal with %j', name, deviceInfo);
175
- callback(new errors.CommandNotFound(name, deviceInfo));
176
- }
177
- });
218
+ });
178
219
  }
179
220
  });
180
221
  }
@@ -190,35 +231,48 @@ function listToObject(commandList) {
190
231
  }
191
232
 
192
233
  function removeFromDate(creationDate, callback) {
193
- const query = { creationDate: { $lt: creationDate } };
234
+ const condition = { creationDate: { $lt: creationDate } };
194
235
 
195
236
  if (Command.model) {
196
- Command.model.find(query).exec(function (error, commandList) {
197
- if (!error && commandList && commandList.length > 0) {
198
- Command.model.deleteOne(query, function (error) {
199
- if (error) {
200
- logger.debug(context, 'Internal MongoDB Error removing expired commands: %s', error);
201
-
202
- callback(new errors.InternalDbError(error));
203
- } else {
204
- logger.debug(
205
- context,
206
- 'Expired commands successfully removed from MongoDB for date [%s]',
207
- creationDate
208
- );
209
-
210
- callback(null, listToObject(commandList));
211
- }
212
- });
213
- }
214
- });
237
+ const query = Command.model.find(condition);
238
+ query
239
+ .exec({})
240
+ .then((commandList) => {
241
+ if (commandList && commandList.length > 0) {
242
+ const queryDel = Command.model.deleteOne(condition);
243
+ queryDel
244
+ .exec({})
245
+ .then(() => {
246
+ logger.debug(
247
+ context,
248
+ 'Expired commands successfully removed from MongoDB for date [%s]',
249
+ creationDate
250
+ );
251
+ callback(null, listToObject(commandList));
252
+ })
253
+ .catch((error) => {
254
+ logger.debug(context, 'Internal MongoDB Error removing expired commands: %s', error);
255
+ callback(new errors.InternalDbError(error));
256
+ });
257
+ }
258
+ })
259
+ .catch((error) => {
260
+ logger.debug(context, 'Internal MongoDB Error looking for expired commands: %s', error);
261
+ });
215
262
  } else {
216
263
  callback(null, []);
217
264
  }
218
265
  }
219
266
 
220
267
  function clear(callback) {
221
- dbService.db.db.dropDatabase(callback);
268
+ mongoose.connection
269
+ .dropDatabase()
270
+ .then(() => {
271
+ callback(null);
272
+ })
273
+ .catch((error) => {
274
+ callback(error);
275
+ });
222
276
  }
223
277
 
224
278
  function init(newConfig, callback) {
@@ -43,7 +43,7 @@ function listCommands(service, subservice, deviceId, callback) {
43
43
  }
44
44
 
45
45
  function addCommand(service, subservice, deviceId, command, callback) {
46
- logger.debug(context, 'Adding command [%j] to the queue for device [%s]', command, deviceId);
46
+ logger.debug(context, 'Adding command [%j] to the queue for deviceId [%s]', command, deviceId);
47
47
  config.getCommandRegistry().add(service, subservice, deviceId, command, callback);
48
48
  }
49
49
 
@@ -73,13 +73,13 @@ function addCommandDevice(service, subservice, device, command, callback) {
73
73
  }
74
74
 
75
75
  function updateCommand(service, subservice, deviceId, name, value, callback) {
76
- logger.debug(context, 'Updating command [%s] for device [%s] with value [%s]', name, deviceId, value);
76
+ logger.debug(context, 'Updating command [%s] for deviceId [%s] with value [%s]', name, deviceId, value);
77
77
 
78
78
  config.getCommandRegistry().update(service, subservice, deviceId, value, callback);
79
79
  }
80
80
 
81
81
  function removeCommand(service, subservice, deviceId, name, callback) {
82
- logger.debug(context, 'Removing command [%s] from device [%s]', name, deviceId);
82
+ logger.debug(context, 'Removing command [%s] from deviceId [%s]', name, deviceId);
83
83
 
84
84
  config.getCommandRegistry().remove(service, subservice, deviceId, name, callback);
85
85
  }
@@ -63,7 +63,9 @@ function register(callback) {
63
63
  entityNameExp: service.entityNameExp,
64
64
  payloadType: service.payloadType,
65
65
  endpoint: service.endpoint,
66
- transport: service.transport
66
+ transport: service.transport,
67
+ useCBflowControl: service.useCBflowControl,
68
+ storeLastMeasure: service.storeLastMeasure
67
69
  };
68
70
  }
69
71
 
@@ -210,8 +210,44 @@ function getDevicesByAttribute(name, value, service, subservice, callback) {
210
210
  }
211
211
  }
212
212
 
213
+ function storeDeviceField(fieldName, fieldValue, typeInformation, callback) {
214
+ if (
215
+ typeInformation &&
216
+ typeInformation.id &&
217
+ typeInformation.apikey &&
218
+ typeInformation.service &&
219
+ typeInformation.subservice
220
+ ) {
221
+ getDevice(
222
+ typeInformation.id,
223
+ typeInformation.apikey,
224
+ typeInformation.service,
225
+ typeInformation.subservice,
226
+ function (error, data) {
227
+ if (!error) {
228
+ if (data) {
229
+ if (fieldName === 'lastMeasure') {
230
+ data.lastMeasure = { timestamp: new Date().toISOString(), measure: fieldValue };
231
+ } else {
232
+ data[fieldName] = fieldValue;
233
+ }
234
+ }
235
+ if (callback) {
236
+ callback(null, data);
237
+ }
238
+ } else {
239
+ callback(error, null);
240
+ }
241
+ }
242
+ );
243
+ } else {
244
+ callback(null, null);
245
+ }
246
+ }
247
+
213
248
  exports.getDevicesByAttribute = getDevicesByAttribute;
214
249
  exports.store = storeDevice;
250
+ exports.storeDeviceField = storeDeviceField;
215
251
  exports.update = update;
216
252
  exports.remove = removeDevice;
217
253
  exports.list = listDevices;