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.
- package/.github/workflows/ci.yml +10 -9
- package/.nyc_output/e4b1fe20-197e-4221-9f8d-6db65ff234b2.json +1 -0
- package/.nyc_output/processinfo/e4b1fe20-197e-4221-9f8d-6db65ff234b2.json +1 -0
- package/.nyc_output/processinfo/index.json +1 -0
- package/Changelog +791 -0
- package/config.js +2 -1
- package/doc/admin.md +20 -4
- package/doc/api.md +34 -4
- package/doc/devel/northboundinteractions.md +200 -112
- package/lib/commonConfig.js +16 -3
- package/lib/model/Device.js +3 -1
- package/lib/model/Group.js +2 -1
- package/lib/services/common/domain.js +4 -3
- package/lib/services/common/iotManagerService.js +2 -1
- package/lib/services/devices/deviceRegistryMongoDB.js +5 -1
- package/lib/services/devices/deviceService.js +17 -1
- package/lib/services/devices/devices-NGSI-LD.js +4 -4
- package/lib/services/devices/devices-NGSI-mixed.js +16 -0
- package/lib/services/devices/devices-NGSI-v2.js +123 -10
- package/lib/services/devices/registrationUtils.js +97 -30
- package/lib/services/groups/groupRegistryMongoDB.js +2 -1
- package/lib/services/ngsi/entities-NGSI-LD.js +69 -13
- package/lib/services/ngsi/ngsiService.js +3 -1
- package/lib/services/ngsi/subscription-NGSI-LD.js +2 -2
- package/lib/services/ngsi/subscription-NGSI-mixed.js +3 -3
- package/lib/services/ngsi/subscription-NGSI-v2.js +20 -6
- package/lib/services/ngsi/subscriptionService.js +2 -2
- package/lib/services/northBound/contextServer-NGSI-LD.js +5 -3
- package/lib/services/northBound/deviceProvisioningServer.js +6 -3
- package/lib/services/northBound/northboundServer.js +1 -1
- package/lib/services/northBound/restUtils.js +6 -2
- package/lib/templates/updateDevice.json +12 -0
- package/lib/templates/updateDeviceLax.json +4 -0
- package/package.json +2 -2
- package/test/functional/config-test.js +1 -1
- package/test/unit/general/contextBrokerKeystoneSecurityAccess-test.js +2 -2
- package/test/unit/memoryRegistry/deviceRegistryMemory_test.js +1 -1
- package/test/unit/ngsi-ld/examples/contextRequests/createDatetimeProvisionedDevice.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDevice.json +3 -12
- package/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDeviceMultientity.json +3 -12
- package/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDeviceWithGroupAndStatic.json +6 -24
- package/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDeviceWithGroupAndStatic2.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContext1.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContext3WithStatic.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContext4.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContext5.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin6.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin7.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin8.json +4 -2
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin9.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextCommandError.json +3 -9
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextCommandExpired.json +13 -19
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextCommandFinish.json +13 -19
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextCommandStatus1.json +4 -9
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextCompressTimestamp1.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextCompressTimestamp2.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin1a.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin2.json +2 -8
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin29.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin4.json +2 -8
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin4a.json +3 -12
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin6.json +3 -5
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin7.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin8a.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextJsonProperty.json +13 -0
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextListProperty.json +14 -0
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextListRelationship.json +14 -0
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin1.json +2 -8
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin2.json +2 -8
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin3.json +3 -8
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin4.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin5.json +2 -8
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin8.json +2 -8
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityTimestampPlugin1.json +2 -8
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityTimestampPlugin2.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityTimestampPlugin3.json +1 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityTimestampPlugin4.json +2 -8
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextRelationship.json +11 -0
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextValueType1.json +51 -0
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextValueType2.json +65 -0
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextVocabProperty.json +11 -0
- package/test/unit/ngsi-ld/examples/contextRequests/updateProvisionCommands1.json +2 -8
- package/test/unit/ngsi-ld/examples/contextRequests/updateProvisionDeviceStatic.json +1 -4
- package/test/unit/ngsi-ld/general/contextBrokerOAuthSecurityAccess-test.js +2 -2
- package/test/unit/ngsi-ld/general/https-support-test.js +1 -1
- package/test/unit/ngsi-ld/general/startup-test.js +3 -0
- package/test/unit/ngsi-ld/lazyAndCommands/command-test.js +1 -1
- package/test/unit/ngsi-ld/lazyAndCommands/lazy-devices-test.js +71 -1
- package/test/unit/ngsi-ld/ngsiService/attributeTypes-test.js +293 -0
- package/test/unit/ngsi-ld/ngsiService/subscriptions-test.js +6 -6
- package/test/unit/ngsi-ld/ngsiService/unsupported-endpoints-test.js +0 -10
- package/test/unit/ngsi-ld/ngsiService/value-types-test.js +221 -0
- package/test/unit/ngsiv2/examples/contextAvailabilityRequests/subscribeIoTAgentCommands.json +24 -0
- package/test/unit/ngsiv2/examples/contextAvailabilityRequests/subscribeIoTAgentCommands2.json +24 -0
- package/test/unit/ngsiv2/examples/contextAvailabilityRequests/subscribeIoTAgentCommands3.json +24 -0
- package/test/unit/ngsiv2/examples/contextAvailabilityRequests/subscribeIoTAgentCommands4.json +24 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateEntity.json +5 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateEntity2.json +5 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateEntity2b.json +7 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateEntity3.json +5 -0
- package/test/unit/ngsiv2/examples/subscriptionRequests/simpleSubscriptionRequest.json +4 -2
- package/test/unit/ngsiv2/examples/subscriptionRequests/simpleSubscriptionRequest2.json +4 -2
- package/test/unit/ngsiv2/general/contextBrokerOAuthSecurityAccess-test.js +2 -2
- package/test/unit/ngsiv2/general/https-support-test.js +1 -1
- package/test/unit/ngsiv2/lazyAndCommands/command-test.js +245 -2
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast1.json +0 -11
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast10.json +0 -14
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast2.json +0 -11
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast3.json +0 -11
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast4.json +0 -11
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast5.json +0 -7
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast6.json +0 -17
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast7.json +0 -19
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast8.json +0 -14
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast9.json +0 -14
- package/test/unit/ngsi-ld/ngsiService/languageProperties-test.js +0 -109
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast1.json +0 -8
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast2.json +0 -8
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast3.json +0 -8
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast4.json +0 -8
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast5.json +0 -8
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast6.json +0 -8
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast7.json +0 -8
- /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
|
-
'
|
|
115
|
-
|
|
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 =
|
|
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
|
-
|
|
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:
|
|
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,
|
|
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:
|
|
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
|
|
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
|
|
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
|
-
|
|
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 && !
|
|
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
|
}
|
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.
|
|
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": ">=
|
|
26
|
+
"node": ">=20"
|
|
27
27
|
},
|
|
28
28
|
"scripts": {
|
|
29
29
|
"clean": "rm -rf package-lock.json && rm -rf node_modules && rm -rf coverage",
|
|
@@ -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(
|
|
246
|
+
Object.keys(device).length.should.equal(13);
|
|
247
247
|
done();
|
|
248
248
|
});
|
|
249
249
|
});
|
|
@@ -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"
|
package/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDeviceWithGroupAndStatic.json
CHANGED
|
@@ -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
|
]
|