iotagent-node-lib 4.8.0 → 4.10.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 (124) hide show
  1. package/.github/workflows/ci.yml +10 -9
  2. package/.nyc_output/e4b1fe20-197e-4221-9f8d-6db65ff234b2.json +1 -0
  3. package/.nyc_output/processinfo/e4b1fe20-197e-4221-9f8d-6db65ff234b2.json +1 -0
  4. package/.nyc_output/processinfo/index.json +1 -0
  5. package/Changelog +791 -0
  6. package/config.js +2 -1
  7. package/doc/admin.md +20 -4
  8. package/doc/api.md +34 -4
  9. package/doc/devel/northboundinteractions.md +200 -112
  10. package/lib/commonConfig.js +16 -3
  11. package/lib/model/Device.js +3 -1
  12. package/lib/model/Group.js +2 -1
  13. package/lib/services/common/domain.js +4 -3
  14. package/lib/services/common/iotManagerService.js +2 -1
  15. package/lib/services/devices/deviceRegistryMongoDB.js +5 -1
  16. package/lib/services/devices/deviceService.js +17 -1
  17. package/lib/services/devices/devices-NGSI-LD.js +4 -4
  18. package/lib/services/devices/devices-NGSI-mixed.js +16 -0
  19. package/lib/services/devices/devices-NGSI-v2.js +123 -10
  20. package/lib/services/devices/registrationUtils.js +97 -30
  21. package/lib/services/groups/groupRegistryMongoDB.js +2 -1
  22. package/lib/services/ngsi/entities-NGSI-LD.js +69 -13
  23. package/lib/services/ngsi/ngsiService.js +3 -1
  24. package/lib/services/ngsi/subscription-NGSI-LD.js +2 -2
  25. package/lib/services/ngsi/subscription-NGSI-mixed.js +3 -3
  26. package/lib/services/ngsi/subscription-NGSI-v2.js +20 -6
  27. package/lib/services/ngsi/subscriptionService.js +2 -2
  28. package/lib/services/northBound/contextServer-NGSI-LD.js +5 -3
  29. package/lib/services/northBound/deviceProvisioningServer.js +6 -3
  30. package/lib/services/northBound/northboundServer.js +1 -1
  31. package/lib/services/northBound/restUtils.js +6 -2
  32. package/lib/templates/updateDevice.json +12 -0
  33. package/lib/templates/updateDeviceLax.json +4 -0
  34. package/package.json +2 -2
  35. package/test/functional/config-test.js +1 -1
  36. package/test/unit/general/contextBrokerKeystoneSecurityAccess-test.js +2 -2
  37. package/test/unit/memoryRegistry/deviceRegistryMemory_test.js +1 -1
  38. package/test/unit/ngsi-ld/examples/contextRequests/createDatetimeProvisionedDevice.json +1 -4
  39. package/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDevice.json +3 -12
  40. package/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDeviceMultientity.json +3 -12
  41. package/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDeviceWithGroupAndStatic.json +6 -24
  42. package/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDeviceWithGroupAndStatic2.json +1 -4
  43. package/test/unit/ngsi-ld/examples/contextRequests/updateContext1.json +1 -4
  44. package/test/unit/ngsi-ld/examples/contextRequests/updateContext3WithStatic.json +1 -4
  45. package/test/unit/ngsi-ld/examples/contextRequests/updateContext4.json +1 -4
  46. package/test/unit/ngsi-ld/examples/contextRequests/updateContext5.json +1 -4
  47. package/test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin6.json +1 -4
  48. package/test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin7.json +1 -4
  49. package/test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin8.json +4 -2
  50. package/test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin9.json +1 -4
  51. package/test/unit/ngsi-ld/examples/contextRequests/updateContextCommandError.json +3 -9
  52. package/test/unit/ngsi-ld/examples/contextRequests/updateContextCommandExpired.json +13 -19
  53. package/test/unit/ngsi-ld/examples/contextRequests/updateContextCommandFinish.json +13 -19
  54. package/test/unit/ngsi-ld/examples/contextRequests/updateContextCommandStatus1.json +4 -9
  55. package/test/unit/ngsi-ld/examples/contextRequests/updateContextCompressTimestamp1.json +1 -4
  56. package/test/unit/ngsi-ld/examples/contextRequests/updateContextCompressTimestamp2.json +1 -4
  57. package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin1a.json +1 -4
  58. package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin2.json +2 -8
  59. package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin29.json +1 -4
  60. package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin4.json +2 -8
  61. package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin4a.json +3 -12
  62. package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin6.json +3 -5
  63. package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin7.json +1 -4
  64. package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin8a.json +1 -4
  65. package/test/unit/ngsi-ld/examples/contextRequests/updateContextJsonProperty.json +13 -0
  66. package/test/unit/ngsi-ld/examples/contextRequests/updateContextListProperty.json +14 -0
  67. package/test/unit/ngsi-ld/examples/contextRequests/updateContextListRelationship.json +14 -0
  68. package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin1.json +2 -8
  69. package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin2.json +2 -8
  70. package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin3.json +3 -8
  71. package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin4.json +1 -4
  72. package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin5.json +2 -8
  73. package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin8.json +2 -8
  74. package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityTimestampPlugin1.json +2 -8
  75. package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityTimestampPlugin2.json +1 -4
  76. package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityTimestampPlugin3.json +1 -4
  77. package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityTimestampPlugin4.json +2 -8
  78. package/test/unit/ngsi-ld/examples/contextRequests/updateContextRelationship.json +11 -0
  79. package/test/unit/ngsi-ld/examples/contextRequests/updateContextValueType1.json +51 -0
  80. package/test/unit/ngsi-ld/examples/contextRequests/updateContextValueType2.json +65 -0
  81. package/test/unit/ngsi-ld/examples/contextRequests/updateContextVocabProperty.json +11 -0
  82. package/test/unit/ngsi-ld/examples/contextRequests/updateProvisionCommands1.json +2 -8
  83. package/test/unit/ngsi-ld/examples/contextRequests/updateProvisionDeviceStatic.json +1 -4
  84. package/test/unit/ngsi-ld/general/contextBrokerOAuthSecurityAccess-test.js +2 -2
  85. package/test/unit/ngsi-ld/general/https-support-test.js +1 -1
  86. package/test/unit/ngsi-ld/general/startup-test.js +3 -0
  87. package/test/unit/ngsi-ld/lazyAndCommands/command-test.js +1 -1
  88. package/test/unit/ngsi-ld/lazyAndCommands/lazy-devices-test.js +71 -1
  89. package/test/unit/ngsi-ld/ngsiService/attributeTypes-test.js +293 -0
  90. package/test/unit/ngsi-ld/ngsiService/subscriptions-test.js +6 -6
  91. package/test/unit/ngsi-ld/ngsiService/unsupported-endpoints-test.js +0 -10
  92. package/test/unit/ngsi-ld/ngsiService/value-types-test.js +221 -0
  93. package/test/unit/ngsiv2/examples/contextAvailabilityRequests/subscribeIoTAgentCommands.json +24 -0
  94. package/test/unit/ngsiv2/examples/contextAvailabilityRequests/subscribeIoTAgentCommands2.json +24 -0
  95. package/test/unit/ngsiv2/examples/contextAvailabilityRequests/subscribeIoTAgentCommands3.json +24 -0
  96. package/test/unit/ngsiv2/examples/contextAvailabilityRequests/subscribeIoTAgentCommands4.json +24 -0
  97. package/test/unit/ngsiv2/examples/contextRequests/updateEntity.json +5 -0
  98. package/test/unit/ngsiv2/examples/contextRequests/updateEntity2.json +5 -0
  99. package/test/unit/ngsiv2/examples/contextRequests/updateEntity2b.json +7 -0
  100. package/test/unit/ngsiv2/examples/contextRequests/updateEntity3.json +5 -0
  101. package/test/unit/ngsiv2/examples/subscriptionRequests/simpleSubscriptionRequest.json +4 -2
  102. package/test/unit/ngsiv2/examples/subscriptionRequests/simpleSubscriptionRequest2.json +4 -2
  103. package/test/unit/ngsiv2/general/contextBrokerOAuthSecurityAccess-test.js +2 -2
  104. package/test/unit/ngsiv2/general/https-support-test.js +1 -1
  105. package/test/unit/ngsiv2/lazyAndCommands/command-test.js +245 -2
  106. package/test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast1.json +0 -11
  107. package/test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast10.json +0 -14
  108. package/test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast2.json +0 -11
  109. package/test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast3.json +0 -11
  110. package/test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast4.json +0 -11
  111. package/test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast5.json +0 -7
  112. package/test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast6.json +0 -17
  113. package/test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast7.json +0 -19
  114. package/test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast8.json +0 -14
  115. package/test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast9.json +0 -14
  116. package/test/unit/ngsi-ld/ngsiService/languageProperties-test.js +0 -109
  117. package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast1.json +0 -8
  118. package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast2.json +0 -8
  119. package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast3.json +0 -8
  120. package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast4.json +0 -8
  121. package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast5.json +0 -8
  122. package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast6.json +0 -8
  123. package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast7.json +0 -8
  124. /package/test/unit/ngsi-ld/examples/contextRequests/{updateContextLanguageProperties1.json → updateContextLanguageProperty.json} +0 -0
@@ -59,10 +59,13 @@ function convertAttrNGSILD(attr) {
59
59
  return undefined;
60
60
  }
61
61
  let obj = { type: 'Property', value: attr.value };
62
+ let hasValueType = true;
62
63
 
63
64
  switch (attr.type.toLowerCase()) {
64
65
  // Properties
65
66
  case 'property':
67
+ hasValueType = false;
68
+ break;
66
69
  case 'string':
67
70
  case 'text':
68
71
  case 'textunrestricted':
@@ -96,24 +99,26 @@ function convertAttrNGSILD(attr) {
96
99
  }
97
100
  break;
98
101
 
102
+ case 'object':
103
+ case 'array':
104
+ try {
105
+ obj.value = JSON.parse(attr.value);
106
+ } catch (e) {
107
+ // Do nothing
108
+ }
109
+ break;
110
+
99
111
  // Temporal Properties
100
112
  case 'datetime':
101
- obj.value = {
102
- '@type': 'DateTime',
103
- '@value': moment.tz(attr.value, 'Etc/UTC').toISOString()
104
- };
113
+ obj.value = moment.tz(attr.value, 'Etc/UTC').toISOString();
105
114
  break;
106
115
  case 'date':
107
- obj.value = {
108
- '@type': 'Date',
109
- '@value': moment.tz(attr.value, 'Etc/UTC').format(moment.HTML5_FMT.DATE)
110
- };
116
+ obj.value = moment.tz(attr.value, 'Etc/UTC').format(moment.HTML5_FMT.DATE);
111
117
  break;
112
118
  case 'time':
113
- obj.value = {
114
- '@type': 'Time',
115
- '@value': moment.tz(attr.value, 'Etc/UTC').format(moment.HTML5_FMT.TIME_SECONDS)
116
- };
119
+ obj.value = moment
120
+ .tz(new Date('0000-01-01 ' + attr.value), 'Etc/UTC')
121
+ .format(moment.HTML5_FMT.TIME_SECONDS);
117
122
  break;
118
123
 
119
124
  // GeoProperties
@@ -121,37 +126,44 @@ function convertAttrNGSILD(attr) {
121
126
  case 'point':
122
127
  case 'geo:point':
123
128
  case 'geo:json':
129
+ hasValueType = false;
124
130
  obj.type = 'GeoProperty';
125
131
  obj.value = NGSIUtils.getLngLats('Point', attr.value);
126
132
  break;
127
133
  case 'linestring':
128
134
  case 'geo:linestring':
135
+ hasValueType = false;
129
136
  obj.type = 'GeoProperty';
130
137
  obj.value = NGSIUtils.getLngLats('LineString', attr.value);
131
138
  break;
132
139
  case 'polygon':
133
140
  case 'geo:polygon':
141
+ hasValueType = false;
134
142
  obj.type = 'GeoProperty';
135
143
  obj.value = NGSIUtils.getLngLats('Polygon', attr.value);
136
144
  break;
137
145
  case 'multipoint':
138
146
  case 'geo:multipoint':
147
+ hasValueType = false;
139
148
  obj.type = 'GeoProperty';
140
149
  obj.value = NGSIUtils.getLngLats('MultiPoint', attr.value);
141
150
  break;
142
151
  case 'multilinestring':
143
152
  case 'geo:multilinestring':
153
+ hasValueType = false;
144
154
  obj.type = 'GeoProperty';
145
155
  obj.value = NGSIUtils.getLngLats('MultiLineString', attr.value);
146
156
  break;
147
157
  case 'multipolygon':
148
158
  case 'geo:multipolygon':
159
+ hasValueType = false;
149
160
  obj.type = 'GeoProperty';
150
161
  obj.value = NGSIUtils.getLngLats('MultiPolygon', attr.value);
151
162
  break;
152
163
 
153
164
  // Relationships
154
165
  case 'relationship':
166
+ hasValueType = false;
155
167
  obj.type = 'Relationship';
156
168
  obj.object = attr.value;
157
169
  delete obj.value;
@@ -159,13 +171,57 @@ function convertAttrNGSILD(attr) {
159
171
 
160
172
  // LanguageProperties
161
173
  case 'languageproperty':
174
+ hasValueType = false;
162
175
  obj.type = 'LanguageProperty';
163
176
  obj.languageMap = attr.value;
164
177
  delete obj.value;
165
178
  break;
166
179
 
180
+ // VocabProperties
181
+ case 'vocabproperty':
182
+ hasValueType = false;
183
+ obj.type = 'VocabProperty';
184
+ obj.vocab = attr.value;
185
+ delete obj.value;
186
+ break;
187
+ // JsonProperties
188
+ case 'jsonproperty':
189
+ hasValueType = false;
190
+ obj.type = 'JsonProperty';
191
+ obj.json = attr.value;
192
+ delete obj.value;
193
+ break;
194
+ // ListProperties
195
+ case 'listproperty':
196
+ hasValueType = false;
197
+ obj.type = 'ListProperty';
198
+ obj.listValue = attr.value;
199
+ delete obj.value;
200
+ break;
201
+ // ListRelationship
202
+ case 'listrelationship':
203
+ hasValueType = false;
204
+ obj.type = 'ListRelationship';
205
+ obj.listObject = attr.value;
206
+ delete obj.value;
207
+ break;
208
+
167
209
  default:
168
- obj.value = { '@type': attr.type, '@value': attr.value };
210
+ obj.value = attr.value;
211
+ }
212
+
213
+ if (hasValueType) {
214
+ switch (config.getConfig().server.ldSupport.dataType) {
215
+ case '@type':
216
+ obj.value = {
217
+ '@type': attr.type,
218
+ '@value': obj.value
219
+ };
220
+ break;
221
+ case 'valueType':
222
+ obj.valueType = attr.type;
223
+ break;
224
+ }
169
225
  }
170
226
 
171
227
  if (!!obj && attr.metadata) {
@@ -95,7 +95,9 @@ function sendUpdateValue(entityName, attributes, typeInformation, token, callbac
95
95
  // check config about store last measure
96
96
  if (typeInformation.storeLastMeasure) {
97
97
  logger.debug(context, 'StoreLastMeasure for %j', typeInformation);
98
- deviceService.storeDeviceField('lastMeasure', attributes, typeInformation, function () {
98
+ let originalMeasure = typeInformation.originalMeasure ? typeInformation.originalMeasure : null;
99
+ deviceService.storeDeviceField('lastMeasure', originalMeasure, typeInformation, function () {
100
+ delete typeInformation.originalMeasure;
99
101
  return entityHandler.sendUpdateValue(entityName, attributes, typeInformation, token, wrappedNewCallback);
100
102
  });
101
103
  } else {
@@ -105,7 +105,7 @@ function createSubscriptionHandlerNgsiLD(device, triggers, store, callback) {
105
105
  * @param {Object} triggers Array with the names of the attributes that would trigger the subscription
106
106
  * @param {Object} content Array with the names of the attributes to retrieve in the notification.
107
107
  */
108
- function subscribeNgsiLD(device, triggers, content, callback) {
108
+ function subscribeNgsiLD(device, triggers, content, attrsFormat, callback) {
109
109
  const options = {
110
110
  method: 'POST',
111
111
  headers: {
@@ -132,7 +132,7 @@ function subscribeNgsiLD(device, triggers, content, callback) {
132
132
  accept: 'application/json'
133
133
  },
134
134
  attributes: content || [],
135
- format: 'normalized'
135
+ format: attrsFormat
136
136
  }
137
137
  }
138
138
  };
@@ -36,11 +36,11 @@ const subscriptionHandlerV2 = require('./subscription-NGSI-v2');
36
36
  * @param {Object} triggers Array with the names of the attributes that would trigger the subscription
37
37
  * @param {Object} content Array with the names of the attributes to retrieve in the notification.
38
38
  */
39
- function subscribeNgsiMixed(device, triggers, content, callback) {
39
+ function subscribeNgsiMixed(device, triggers, content, attrsFormat, callback) {
40
40
  if (config.checkNgsiLD(device)) {
41
- subscriptionHandlerLD.subscribe(device, triggers, content, callback);
41
+ subscriptionHandlerLD.subscribe(device, triggers, content, attrsFormat, callback);
42
42
  } else {
43
- subscriptionHandlerV2.subscribe(device, triggers, content, callback);
43
+ subscriptionHandlerV2.subscribe(device, triggers, content, attrsFormat, callback);
44
44
  }
45
45
  }
46
46
 
@@ -93,7 +93,9 @@ function createSubscriptionHandlerNgsi2(device, triggers, store, callback) {
93
93
 
94
94
  config.getRegistry().update(device, device, callback);
95
95
  } else {
96
- callback(null, response.headers.location);
96
+ callback(null, {
97
+ subscriptionId: response.headers.location.substr(response.headers.location.lastIndexOf('/') + 1)
98
+ });
97
99
  }
98
100
  };
99
101
  }
@@ -107,7 +109,7 @@ function createSubscriptionHandlerNgsi2(device, triggers, store, callback) {
107
109
  * @param {Object} triggers Array with the names of the attributes that would trigger the subscription
108
110
  * @param {Object} content Array with the names of the attributes to retrieve in the notification.
109
111
  */
110
- function subscribeNgsi2(device, triggers, content, callback) {
112
+ function subscribeNgsi2(device, triggers, content, attrsFormat, callback) {
111
113
  const options = {
112
114
  method: 'POST',
113
115
  headers: {
@@ -115,6 +117,7 @@ function subscribeNgsi2(device, triggers, content, callback) {
115
117
  'fiware-servicepath': device.subservice
116
118
  },
117
119
  json: {
120
+ description: 'Managed by IOTA: ' + device.name + ' ' + device.type + ' ' + triggers.join(','),
118
121
  subject: {
119
122
  entities: [
120
123
  {
@@ -132,7 +135,8 @@ function subscribeNgsi2(device, triggers, content, callback) {
132
135
  url: config.getConfig().providerUrl + '/notify'
133
136
  },
134
137
  attrs: content || [],
135
- attrsFormat: 'normalized'
138
+ attrsFormat: attrsFormat,
139
+ onlyChangedAttrs: true
136
140
  }
137
141
  }
138
142
  };
@@ -167,7 +171,7 @@ function createUnsubscribeHandlerNgsi2(device, id, callback) {
167
171
  if (error) {
168
172
  logger.debug(
169
173
  context,
170
- 'Transport error found subscribing device with id [%s] to entity [%s]',
174
+ 'Transport error found unsubscribing device with id [%s] to entity [%s]',
171
175
  device.id,
172
176
  device.name
173
177
  );
@@ -176,7 +180,9 @@ function createUnsubscribeHandlerNgsi2(device, id, callback) {
176
180
  } else if (response.statusCode !== 204) {
177
181
  logger.debug(
178
182
  context,
179
- 'Unknown error subscribing device with id [%s] to entity [%s]: $s',
183
+ 'Unknown error unsubscribing device with id [%s] to entity [%s]: %s',
184
+ device.id,
185
+ device.name,
180
186
  response.statusCode
181
187
  );
182
188
 
@@ -202,7 +208,15 @@ function createUnsubscribeHandlerNgsi2(device, id, callback) {
202
208
 
203
209
  callback(new errors.BadRequest(body.orionError.details));
204
210
  } else {
205
- device.subscriptions.splice(device.subscriptions.indexOf(id), 1);
211
+ logger.debug(context, 'removing subscription %s from device %j', id, device);
212
+ if (device.subscriptions) {
213
+ // check before try to eliminates
214
+ const index = device.subscriptions.indexOf(id);
215
+ if (index !== -1) {
216
+ // only eliminates if exits
217
+ device.subscriptions.splice(index, 1);
218
+ }
219
+ }
206
220
  config.getRegistry().update(device, device, callback);
207
221
  }
208
222
  };
@@ -57,8 +57,8 @@ function init() {
57
57
  * @param {Object} triggers Array with the names of the attributes that would trigger the subscription
58
58
  * @param {Object} content Array with the names of the attributes to retrieve in the notification.
59
59
  */
60
- function subscribe(device, triggers, content, callback) {
61
- subscriptionHandler.subscribe(device, triggers, content, callback);
60
+ function subscribe(device, triggers, content, attrsFormat, callback) {
61
+ subscriptionHandler.subscribe(device, triggers, content, attrsFormat, callback);
62
62
  }
63
63
 
64
64
  /**
@@ -46,7 +46,7 @@ const config = require('../../commonConfig');
46
46
 
47
47
  const overwritePaths = ['/ngsi-ld/v1/entities/:entity/attrs', '/ngsi-ld/v1/entities/:entity/attrs/:attr'];
48
48
  const updatePaths = ['/ngsi-ld/v1/entities/:entity/attrs', '/ngsi-ld/v1/entities/:entity/attrs/:attr'];
49
- const queryPaths = ['/ngsi-ld/v1/entities/:entity'];
49
+ const queryPaths = ['/ngsi-ld/v1/entities/:entity', '/ngsi-ld/v1/entities'];
50
50
 
51
51
  /**
52
52
  * Replacement of NGSI-LD Null placeholders with real null values
@@ -506,6 +506,9 @@ function handleMergePatchNgsiLD(req, res, next) {
506
506
  * @param {Object} res Response that will be sent.
507
507
  */
508
508
  function handleQueryNgsiLD(req, res, next) {
509
+ const returnAsArray = req.query.id;
510
+ req.params.entity = req.params.entity || req.query.id || '';
511
+
509
512
  function getName(element) {
510
513
  return element.name;
511
514
  }
@@ -641,7 +644,7 @@ function handleQueryNgsiLD(req, res, next) {
641
644
  next(error);
642
645
  } else {
643
646
  logger.debug(context, 'Query from [%s] handled successfully.', req.get('host'));
644
- res.status(200).json(result);
647
+ res.status(200).json(returnAsArray ? [result] : result);
645
648
  }
646
649
  }
647
650
 
@@ -793,7 +796,6 @@ function loadUnsupportedEndpointsNGSILD(router) {
793
796
  const unsupportedEndpoint = function (req, res) {
794
797
  return res.status(501).send(new errors.MethodNotSupported(req.method, req.path));
795
798
  };
796
- router.get('/ngsi-ld/v1/entities', unsupportedEndpoint);
797
799
  router.post('/ngsi-ld/v1/entities', unsupportedEndpoint);
798
800
  router.delete('/ngsi-ld/v1/entities/:entity', unsupportedEndpoint);
799
801
  router.delete('/ngsi-ld/v1/entities/:entity/attrs/:attr', unsupportedEndpoint);
@@ -67,7 +67,8 @@ const provisioningAPITranslation = {
67
67
  payloadType: 'payloadType',
68
68
  useCBflowControl: 'useCBflowControl',
69
69
  storeLastMeasure: 'storeLastMeasure',
70
- lastMeasure: 'lastMeasure'
70
+ lastMeasure: 'lastMeasure',
71
+ cmdMode: 'cmdMode'
71
72
  };
72
73
 
73
74
  /**
@@ -149,7 +150,8 @@ function handleProvision(req, res, next) {
149
150
  payloadType: body.payloadType,
150
151
  useCBflowControl: body.useCBflowControl,
151
152
  storeLastMeasure: body.storeLastMeasure,
152
- lastMeasure: body.lastMeasure
153
+ lastMeasure: body.lastMeasure,
154
+ cmdMode: body.cmdMode
153
155
  });
154
156
  }
155
157
 
@@ -229,7 +231,8 @@ function toProvisioningAPIFormat(device) {
229
231
  payloadType: device.payloadType,
230
232
  useCBflowControl: device.useCBflowControl,
231
233
  storeLastMeasure: device.storeLastMeasure,
232
- lastMeasure: device.lastMeasure
234
+ lastMeasure: device.lastMeasure,
235
+ cmdMode: device.cmdMode
233
236
  };
234
237
  }
235
238
 
@@ -59,7 +59,7 @@ function start(config, callback) {
59
59
  northboundServer.app.use(domainUtils.requestDomain);
60
60
  northboundServer.app.use(bodyParser.json({ limit: config.expressLimit }));
61
61
  northboundServer.app.use(bodyParser.json({ type: 'application/*+json', limit: config.expressLimit }));
62
-
62
+ northboundServer.app.set('trust proxy', true); // populate req.ip
63
63
  if (config.logLevel && config.logLevel === 'DEBUG') {
64
64
  northboundServer.app.use(middlewares.traceRequest);
65
65
  }
@@ -30,7 +30,6 @@ const errors = require('../../errors');
30
30
  const constants = require('../../constants');
31
31
  const intoTrans = require('../common/domain').intoTrans;
32
32
  const revalidator = require('revalidator');
33
- const moment = require('moment');
34
33
  const context = {
35
34
  op: 'IoTAgentNGSI.RestUtils'
36
35
  };
@@ -121,6 +120,11 @@ function checkBody(template) {
121
120
  };
122
121
  }
123
122
 
123
+ function isISOString(val) {
124
+ const d = new Date(val);
125
+ return !Number.isNaN(d.valueOf()) && d.toISOString() === val;
126
+ }
127
+
124
128
  /**
125
129
  * Checks if the timestamp properties of NGSIv2 entities are valid ISO8601 dates.
126
130
  *
@@ -131,7 +135,7 @@ function IsValidTimestampedNgsi2(payload) {
131
135
  function isValidTimestampedNgsi2Entity(entity) {
132
136
  for (const i in entity) {
133
137
  if (entity.hasOwnProperty(i)) {
134
- if (i === constants.TIMESTAMP_ATTRIBUTE && !moment(entity[i].value, moment.ISO_8601).isValid()) {
138
+ if (i === constants.TIMESTAMP_ATTRIBUTE && !isISOString(entity[i].value)) {
135
139
  return false;
136
140
  }
137
141
  }
@@ -157,6 +157,10 @@
157
157
  "description": "use CB flowControl option",
158
158
  "type": "boolean"
159
159
  },
160
+ "cmdMode": {
161
+ "description": "CB commands mode",
162
+ "type": "string"
163
+ },
160
164
  "contentType": {
161
165
  "description": "Content type",
162
166
  "type": "string"
@@ -203,6 +207,10 @@
203
207
  "description": "Payload type allowed for measures for this device",
204
208
  "type": "string"
205
209
  },
210
+ "useCBflowControl": {
211
+ "description": "use CB flowControl option",
212
+ "type": "boolean"
213
+ },
206
214
  "storeLastMeasure": {
207
215
  "description": "Store last measure",
208
216
  "type": "boolean"
@@ -210,6 +218,10 @@
210
218
  "lastMeasure": {
211
219
  "description": "last measure",
212
220
  "type": "object"
221
+ },
222
+ "cmdMode": {
223
+ "description": "CB commands mode",
224
+ "type": "string"
213
225
  }
214
226
  }
215
227
  }
@@ -158,6 +158,10 @@
158
158
  "lastMeasure": {
159
159
  "description": "last measure",
160
160
  "type": "object"
161
+ },
162
+ "cmdMode": {
163
+ "description": "CB commands mode",
164
+ "type": "string"
161
165
  }
162
166
  }
163
167
  }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "iotagent-node-lib",
3
3
  "license": "AGPL-3.0-only",
4
4
  "description": "IoT Agent library to interface with NGSI Context Broker",
5
- "version": "4.8.0",
5
+ "version": "4.10.0",
6
6
  "homepage": "https://github.com/telefonicaid/iotagent-node-lib",
7
7
  "keywords": [
8
8
  "fiware",
@@ -23,7 +23,7 @@
23
23
  },
24
24
  "main": "lib/fiware-iotagent-lib",
25
25
  "engines": {
26
- "node": ">=16"
26
+ "node": ">=20"
27
27
  },
28
28
  "scripts": {
29
29
  "clean": "rm -rf package-lock.json && rm -rf node_modules && rm -rf coverage",
@@ -45,7 +45,7 @@ config.amqp = {
45
45
  };
46
46
 
47
47
  config.iota = {
48
- logLevel: 'DEBUG',
48
+ logLevel: 'FATAL',
49
49
  contextBroker: {
50
50
  host: '192.168.1.1',
51
51
  port: '1026',
@@ -295,7 +295,7 @@ describe('NGSI-v2 - Secured access to the Context Broker with Keystone', functio
295
295
 
296
296
  it('subscribe requests use auth header', function (done) {
297
297
  iotAgentLib.getDevice('Light1', null, 'smartgondor', 'electricity', function (error, device) {
298
- iotAgentLib.subscribe(device, ['dimming'], null, function (error) {
298
+ iotAgentLib.subscribe(device, ['dimming'], null, 'normalized', function (error) {
299
299
  should.not.exist(error);
300
300
 
301
301
  contextBrokerMock.done();
@@ -316,7 +316,7 @@ describe('NGSI-v2 - Secured access to the Context Broker with Keystone', functio
316
316
  });
317
317
 
318
318
  iotAgentLib.getDevice('Light1', null, 'smartgondor', 'electricity', function (error, device) {
319
- iotAgentLib.subscribe(device, ['dimming'], null, function (error) {
319
+ iotAgentLib.subscribe(device, ['dimming'], null, 'normalized', function (error) {
320
320
  iotAgentLib.unsubscribe(device, '51c0ac9ed714fb3b37d7d5a8', function (error) {
321
321
  contextBrokerMock.done();
322
322
  done();
@@ -243,7 +243,7 @@ describe('NGSI-v2 - In memory device registry', function () {
243
243
  should.exist(device.type);
244
244
  device.name.should.equal('name5');
245
245
  device.type.should.equal('Light5');
246
- Object.keys(device).length.should.equal(12);
246
+ Object.keys(device).length.should.equal(13);
247
247
  done();
248
248
  });
249
249
  });
@@ -4,10 +4,7 @@
4
4
  "id": "urn:ngsi-ld:MicroLights:FirstMicroLight",
5
5
  "timestamp": {
6
6
  "type": "Property",
7
- "value": {
8
- "@type": "DateTime",
9
- "@value": "1970-01-01T00:00:00.000Z"
10
- }
7
+ "value": "1970-01-01T00:00:00.000Z"
11
8
  },
12
9
  "type": "MicroLights"
13
10
  }
@@ -3,24 +3,15 @@
3
3
  "@context": "http://context.json-ld",
4
4
  "commandAttr_info": {
5
5
  "type": "Property",
6
- "value": {
7
- "@type": "commandResult",
8
- "@value": " "
9
- }
6
+ "value": " "
10
7
  },
11
8
  "commandAttr_status": {
12
9
  "type": "Property",
13
- "value": {
14
- "@type": "commandStatus",
15
- "@value": "UNKNOWN"
16
- }
10
+ "value": "UNKNOWN"
17
11
  },
18
12
  "hardcodedAttr": {
19
13
  "type": "Property",
20
- "value": {
21
- "@type": "hardcodedType",
22
- "@value": "hardcodedValue"
23
- }
14
+ "value": "hardcodedValue"
24
15
  },
25
16
  "id": "urn:ngsi-ld:TheLightType:TheFirstLight",
26
17
  "type": "TheLightType"
@@ -3,24 +3,15 @@
3
3
  "@context": "http://context.json-ld",
4
4
  "commandAttr_info": {
5
5
  "type": "Property",
6
- "value": {
7
- "@type": "commandResult",
8
- "@value": " "
9
- }
6
+ "value": " "
10
7
  },
11
8
  "commandAttr_status": {
12
9
  "type": "Property",
13
- "value": {
14
- "@type": "commandStatus",
15
- "@value": "UNKNOWN"
16
- }
10
+ "value": "UNKNOWN"
17
11
  },
18
12
  "hardcodedAttr": {
19
13
  "type": "Property",
20
- "value": {
21
- "@type": "hardcodedType",
22
- "@value": "hardcodedValue"
23
- }
14
+ "value": "hardcodedType"
24
15
  },
25
16
  "id": "urn:ngsi-ld:TheLightType:TheFirstLight",
26
17
  "type": "TheLightType"
@@ -5,45 +5,27 @@
5
5
  "type": "TheLightType",
6
6
  "hardcodedAttr": {
7
7
  "type": "Property",
8
- "value": {
9
- "@type": "hardcodedType",
10
- "@value": "hardcodedValue"
11
- }
8
+ "value": "hardcodedType"
12
9
  },
13
10
  "bootstrapServer": {
14
11
  "type": "Property",
15
- "value": {
16
- "@type": "Address",
17
- "@value": "127.0.0.1"
18
- }
12
+ "value": "127.0.0.1"
19
13
  },
20
14
  "commandAttr_status": {
21
15
  "type": "Property",
22
- "value": {
23
- "@type": "commandStatus",
24
- "@value": "UNKNOWN"
25
- }
16
+ "value": "UNKNOWN"
26
17
  },
27
18
  "commandAttr_info": {
28
19
  "type": "Property",
29
- "value": {
30
- "@type": "commandResult",
31
- "@value": " "
32
- }
20
+ "value": "commandResult",
33
21
  },
34
22
  "wheel1_status": {
35
23
  "type": "Property",
36
- "value": {
37
- "@type": "commandStatus",
38
- "@value": "UNKNOWN"
39
- }
24
+ "value": "commandStatus"
40
25
  },
41
26
  "wheel1_info": {
42
27
  "type": "Property",
43
- "value": {
44
- "@type": "commandResult",
45
- "@value": " "
46
- }
28
+ "value": "commandResult"
47
29
  }
48
30
  }
49
31
  ]
@@ -9,10 +9,7 @@
9
9
  },
10
10
  "bootstrapServer": {
11
11
  "type": "Property",
12
- "value": {
13
- "@type": "Address",
14
- "@value": "127.0.0.1"
15
- }
12
+ "value": "127.0.0.1"
16
13
  }
17
14
  }
18
15
  ]
@@ -3,10 +3,7 @@
3
3
  "@context": "http://context.json-ld",
4
4
  "dimming": {
5
5
  "type": "Property",
6
- "value": {
7
- "@type": "Percentage",
8
- "@value": "87"
9
- }
6
+ "value": "87"
10
7
  },
11
8
  "id": "urn:ngsi-ld:Light:light1",
12
9
  "state": {
@@ -3,10 +3,7 @@
3
3
  "@context": "http://context.json-ld",
4
4
  "bootstrapServer": {
5
5
  "type": "Property",
6
- "value": {
7
- "@type": "Address",
8
- "@value": "127.0.0.1"
9
- }
6
+ "value": "127.0.0.1"
10
7
  },
11
8
  "id": "urn:ngsi-ld:SensorMachine:machine1",
12
9
  "status": {