iotagent-node-lib 4.7.0 → 4.9.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 +6 -3
- 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/CHANGES_NEXT_RELEASE +1 -0
- package/Changelog +793 -0
- package/doc/README.md +1 -0
- package/doc/admin.md +8 -4
- package/doc/api.md +8 -4
- package/doc/devel/northboundinteractions.md +122 -15
- package/doc/models/models.md +260 -0
- package/doc/requirements.txt +1 -1
- package/docker/Mosquitto/Dockerfile +1 -1
- package/lib/commonConfig.js +11 -2
- package/lib/fiware-iotagent-lib.js +15 -11
- package/lib/jexlTranformsMap.js +182 -35
- package/lib/model/Command.js +9 -0
- package/lib/model/Device.js +1 -0
- package/lib/services/commands/commandRegistryMongoDB.js +15 -1
- package/lib/services/commands/commandService.js +3 -3
- package/lib/services/common/domain.js +4 -3
- package/lib/services/devices/deviceRegistryMongoDB.js +1 -1
- package/lib/services/devices/deviceService.js +11 -2
- package/lib/services/devices/devices-NGSI-LD.js +1 -2
- package/lib/services/devices/devices-NGSI-v2.js +1 -2
- package/lib/services/ngsi/entities-NGSI-LD.js +69 -13
- package/lib/services/ngsi/ngsiService.js +3 -1
- package/lib/services/northBound/contextServer-NGSI-LD.js +5 -3
- package/lib/services/northBound/contextServer-NGSI-v2.js +12 -3
- package/lib/services/northBound/contextServer.js +2 -1
- package/lib/services/northBound/northboundServer.js +2 -1
- package/lib/services/northBound/restUtils.js +6 -2
- package/lib/templates/createDevice.json +4 -0
- package/lib/templates/updateDevice.json +4 -0
- package/package.json +1 -1
- package/test/functional/config-test.js +1 -1
- package/test/functional/testUtils.js +13 -2
- package/test/unit/expressions/jexlExpression-test.js +165 -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/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/unsupported-endpoints-test.js +0 -10
- package/test/unit/ngsi-ld/ngsiService/value-types-test.js +221 -0
- 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/ngsiv2/ngsiService/subscriptions-test.js +0 -326
- /package/test/unit/ngsi-ld/examples/contextRequests/{updateContextLanguageProperties1.json → updateContextLanguageProperty.json} +0 -0
package/lib/jexlTranformsMap.js
CHANGED
|
@@ -26,63 +26,210 @@
|
|
|
26
26
|
JEXL avaliable transformations*/
|
|
27
27
|
|
|
28
28
|
const map = {
|
|
29
|
-
jsonparse: (
|
|
30
|
-
|
|
29
|
+
jsonparse: (val) => {
|
|
30
|
+
const safeOperation =
|
|
31
|
+
(fn) =>
|
|
32
|
+
(...args) => {
|
|
33
|
+
try {
|
|
34
|
+
return fn(...args);
|
|
35
|
+
} catch (e) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
return safeOperation(JSON.parse)(val);
|
|
40
|
+
},
|
|
41
|
+
jsonstringify: (val) => {
|
|
42
|
+
const safeOperation =
|
|
43
|
+
(fn) =>
|
|
44
|
+
(...args) => {
|
|
45
|
+
try {
|
|
46
|
+
return fn(...args);
|
|
47
|
+
} catch (e) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
return safeOperation(JSON.stringify)(val);
|
|
52
|
+
},
|
|
31
53
|
indexOf: (val, char) => String(val).indexOf(char),
|
|
32
54
|
length: (val) => String(val).length,
|
|
33
55
|
trim: (val) => String(val).trim(),
|
|
34
56
|
substr: (val, int1, int2) => String(val).substr(int1, int2),
|
|
35
|
-
addreduce: (arr) =>
|
|
57
|
+
addreduce: (arr) => {
|
|
58
|
+
const safeOperation =
|
|
59
|
+
(fn) =>
|
|
60
|
+
(...args) => {
|
|
61
|
+
try {
|
|
62
|
+
return fn(...args);
|
|
63
|
+
} catch (e) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
return safeOperation((arr) => arr.reduce((i, v) => i + v))(arr);
|
|
68
|
+
},
|
|
36
69
|
lengtharray: (arr) => arr.length,
|
|
37
70
|
typeof: (val) => typeof val,
|
|
38
|
-
isarray:
|
|
39
|
-
isnan:
|
|
40
|
-
parseint: (val) =>
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
71
|
+
isarray: Array.isArray,
|
|
72
|
+
isnan: isNaN,
|
|
73
|
+
parseint: (val) => {
|
|
74
|
+
const safeParseNumber = (fn) => (val) => {
|
|
75
|
+
const result = fn(val);
|
|
76
|
+
return isNaN(result) ? null : result;
|
|
77
|
+
};
|
|
78
|
+
return safeParseNumber((val) => parseInt(val, 10))(val);
|
|
79
|
+
},
|
|
80
|
+
parsefloat: (val) => {
|
|
81
|
+
const safeParseNumber = (fn) => (val) => {
|
|
82
|
+
const result = fn(val);
|
|
83
|
+
return isNaN(result) ? null : result;
|
|
84
|
+
};
|
|
85
|
+
return safeParseNumber(parseFloat)(val);
|
|
86
|
+
},
|
|
87
|
+
toisodate: (val) => {
|
|
88
|
+
const safeDateOperation = (fn) => (val) => {
|
|
89
|
+
const date = new Date(val);
|
|
90
|
+
return isNaN(date.getTime()) ? null : fn(date);
|
|
91
|
+
};
|
|
92
|
+
return safeDateOperation((date) => date.toISOString())(val);
|
|
93
|
+
},
|
|
94
|
+
timeoffset: (val) => {
|
|
95
|
+
const safeDateOperation = (fn) => (val) => {
|
|
96
|
+
const date = new Date(val);
|
|
97
|
+
return isNaN(date.getTime()) ? null : fn(date);
|
|
98
|
+
};
|
|
99
|
+
return safeDateOperation((date) => date.getTimezoneOffset())(val);
|
|
100
|
+
},
|
|
101
|
+
tostring: (val) => {
|
|
102
|
+
const safeOperation =
|
|
103
|
+
(fn) =>
|
|
104
|
+
(...args) => {
|
|
105
|
+
try {
|
|
106
|
+
return fn(...args);
|
|
107
|
+
} catch (e) {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
return safeOperation((val) => val.toString())(val);
|
|
112
|
+
},
|
|
113
|
+
urlencode: encodeURI,
|
|
114
|
+
urldecode: (val) => {
|
|
115
|
+
const safeOperation =
|
|
116
|
+
(fn) =>
|
|
117
|
+
(...args) => {
|
|
118
|
+
try {
|
|
119
|
+
return fn(...args);
|
|
120
|
+
} catch (e) {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
return safeOperation(decodeURI)(val);
|
|
125
|
+
},
|
|
47
126
|
replacestr: (str, from, to) => str.replace(from, to),
|
|
48
|
-
replaceregexp: (str, reg, to) =>
|
|
49
|
-
|
|
50
|
-
|
|
127
|
+
replaceregexp: (str, reg, to) => {
|
|
128
|
+
const safeOperation =
|
|
129
|
+
(fn) =>
|
|
130
|
+
(...args) => {
|
|
131
|
+
try {
|
|
132
|
+
return fn(...args);
|
|
133
|
+
} catch (e) {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
return safeOperation((str, reg, to) => str.replace(new RegExp(reg), to))(str, reg, to);
|
|
138
|
+
},
|
|
139
|
+
replaceallregexp: (str, reg, to) => {
|
|
140
|
+
const safeOperation =
|
|
141
|
+
(fn) =>
|
|
142
|
+
(...args) => {
|
|
143
|
+
try {
|
|
144
|
+
return fn(...args);
|
|
145
|
+
} catch (e) {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
return safeOperation((str, reg, to) => str.replace(new RegExp(reg, 'g'), to))(str, reg, to);
|
|
150
|
+
},
|
|
51
151
|
split: (str, ch) => str.split(ch),
|
|
52
152
|
joinarrtostr: (arr, ch) => arr.join(ch),
|
|
53
153
|
concatarr: (arr, arr2) => arr.concat(arr2),
|
|
54
154
|
mapper: (val, values, choices) => choices[values.findIndex((target) => target === val)],
|
|
55
155
|
thmapper: (val, values, choices) =>
|
|
56
|
-
choices[
|
|
57
|
-
values.reduce((acc, curr, i) => (acc === 0 || acc ? acc : val <= curr ? (acc = i) : (acc = null)), null)
|
|
58
|
-
],
|
|
156
|
+
choices[values.reduce((acc, curr, i) => (acc !== null ? acc : val <= curr ? i : null), null)],
|
|
59
157
|
bitwisemask: (i, mask, op, shf) =>
|
|
60
158
|
(op === '&' ? parseInt(i) & mask : op === '|' ? parseInt(i) | mask : op === '^' ? parseInt(i) ^ mask : i) >>
|
|
61
159
|
shf,
|
|
62
160
|
slice: (arr, init, end) => arr.slice(init, end),
|
|
63
|
-
addset: (arr, x) =>
|
|
64
|
-
return Array.from(new Set(arr).add(x));
|
|
65
|
-
},
|
|
161
|
+
addset: (arr, x) => Array.from(new Set(arr).add(x)),
|
|
66
162
|
removeset: (arr, x) => {
|
|
67
|
-
|
|
163
|
+
const s = new Set(arr);
|
|
68
164
|
s.delete(x);
|
|
69
165
|
return Array.from(s);
|
|
70
166
|
},
|
|
71
167
|
touppercase: (val) => String(val).toUpperCase(),
|
|
72
168
|
tolowercase: (val) => String(val).toLowerCase(),
|
|
73
|
-
floor:
|
|
74
|
-
ceil:
|
|
75
|
-
round:
|
|
76
|
-
tofixed: (val, decimals) =>
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
169
|
+
floor: Math.floor,
|
|
170
|
+
ceil: Math.ceil,
|
|
171
|
+
round: Math.round,
|
|
172
|
+
tofixed: (val, decimals) => {
|
|
173
|
+
const num = Number.parseFloat(val);
|
|
174
|
+
const dec = Number.parseInt(decimals);
|
|
175
|
+
return isNaN(num) || isNaN(dec) ? null : num.toFixed(dec);
|
|
176
|
+
},
|
|
177
|
+
gettime: (val) => {
|
|
178
|
+
const safeDateOperation = (fn) => (val) => {
|
|
179
|
+
const date = new Date(val);
|
|
180
|
+
return isNaN(date.getTime()) ? null : fn(date);
|
|
181
|
+
};
|
|
182
|
+
return safeDateOperation((date) => date.getTime())(val);
|
|
183
|
+
},
|
|
184
|
+
toisostring: (val) => {
|
|
185
|
+
const safeDateOperation = (fn) => (val) => {
|
|
186
|
+
const date = new Date(val);
|
|
187
|
+
return isNaN(date.getTime()) ? null : fn(date);
|
|
188
|
+
};
|
|
189
|
+
return safeDateOperation((date) => date.toISOString())(val);
|
|
190
|
+
},
|
|
191
|
+
localestring: (d, timezone, options) => {
|
|
192
|
+
const safeOperation =
|
|
193
|
+
(fn) =>
|
|
194
|
+
(...args) => {
|
|
195
|
+
try {
|
|
196
|
+
return fn(...args);
|
|
197
|
+
} catch (e) {
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
return safeOperation((d, timezone, options) => new Date(d).toLocaleString(timezone, options))(
|
|
202
|
+
d,
|
|
203
|
+
timezone,
|
|
204
|
+
options
|
|
205
|
+
);
|
|
206
|
+
},
|
|
207
|
+
now: Date.now,
|
|
208
|
+
hextostring: (val) => {
|
|
209
|
+
const safeOperation =
|
|
210
|
+
(fn) =>
|
|
211
|
+
(...args) => {
|
|
212
|
+
try {
|
|
213
|
+
return fn(...args);
|
|
214
|
+
} catch (e) {
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
return safeOperation((val) => {
|
|
219
|
+
if (typeof val !== 'string' || !/^[0-9a-fA-F]+$/.test(val) || val.length % 2 !== 0) {
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
return new TextDecoder().decode(new Uint8Array(val.match(/.{1,2}/g).map((byte) => parseInt(byte, 16))));
|
|
223
|
+
})(val);
|
|
224
|
+
},
|
|
225
|
+
valuePicker: (val, pick) =>
|
|
226
|
+
Object.entries(val)
|
|
227
|
+
.filter(([, v]) => v === pick)
|
|
228
|
+
.map(([k]) => k),
|
|
229
|
+
valuePickerMulti: (val, pick) =>
|
|
230
|
+
Object.entries(val)
|
|
231
|
+
.filter(([, v]) => pick.includes(v))
|
|
232
|
+
.map(([k]) => k)
|
|
86
233
|
};
|
|
87
234
|
|
|
88
235
|
exports.map = map;
|
package/lib/model/Command.js
CHANGED
|
@@ -31,6 +31,15 @@ const Command = new Schema({
|
|
|
31
31
|
value: Object,
|
|
32
32
|
service: { type: String, lowercase: true },
|
|
33
33
|
subservice: String,
|
|
34
|
+
execTs: { type: Date },
|
|
35
|
+
status: String,
|
|
36
|
+
info: String,
|
|
37
|
+
onDelivered: Object,
|
|
38
|
+
onOk: Object,
|
|
39
|
+
onError: Object,
|
|
40
|
+
onInfo: Object,
|
|
41
|
+
cmdExecution: Boolean,
|
|
42
|
+
dateExpiration: { type: Date },
|
|
34
43
|
creationDate: { type: Date, default: Date.now }
|
|
35
44
|
});
|
|
36
45
|
|
package/lib/model/Device.js
CHANGED
|
@@ -89,7 +89,21 @@ function updateCommand(service, subservice, deviceId, command, callback) {
|
|
|
89
89
|
function createCommand(service, subservice, deviceId, command, callback) {
|
|
90
90
|
/* eslint-disable-next-line new-cap */
|
|
91
91
|
const commandObj = new Command.model();
|
|
92
|
-
const attributeList = [
|
|
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
|
+
];
|
|
93
107
|
|
|
94
108
|
for (let i = 0; i < attributeList.length; i++) {
|
|
95
109
|
commandObj[attributeList[i]] = command[attributeList[i]];
|
|
@@ -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
|
|
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
|
|
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
|
|
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
|
}
|
|
@@ -68,7 +68,7 @@ function requestDomain(req, res, next) {
|
|
|
68
68
|
reqDomain.path = req.path;
|
|
69
69
|
reqDomain.op = req.url;
|
|
70
70
|
reqDomain.start = Date.now();
|
|
71
|
-
|
|
71
|
+
reqDomain.from = req.ip || req.connection.remoteAddress;
|
|
72
72
|
reqDomain.add(req);
|
|
73
73
|
reqDomain.add(res);
|
|
74
74
|
|
|
@@ -145,14 +145,15 @@ function ensureSouthboundTransaction(context, callback) {
|
|
|
145
145
|
if (context.op) {
|
|
146
146
|
reqDomain.op = context.op;
|
|
147
147
|
}
|
|
148
|
-
|
|
149
148
|
if (context.srv) {
|
|
150
149
|
reqDomain.service = context.srv;
|
|
151
150
|
}
|
|
152
|
-
|
|
153
151
|
if (context.subsrv) {
|
|
154
152
|
reqDomain.subservice = context.subsrv;
|
|
155
153
|
}
|
|
154
|
+
if (context.from) {
|
|
155
|
+
reqDomain.from = context.from;
|
|
156
|
+
}
|
|
156
157
|
}
|
|
157
158
|
|
|
158
159
|
return reqDomain.run(callback);
|
|
@@ -90,7 +90,7 @@ function storeDevice(newDevice, callback) {
|
|
|
90
90
|
if (error.code === 11000) {
|
|
91
91
|
logger.debug(context, 'Tried to insert a device with duplicate ID in the database: %s', error);
|
|
92
92
|
|
|
93
|
-
callback(new errors.DuplicateDeviceId(newDevice));
|
|
93
|
+
callback(new errors.DuplicateDeviceId(newDevice), newDevice);
|
|
94
94
|
} else {
|
|
95
95
|
logger.debug(context, 'Error storing device information: %s', error);
|
|
96
96
|
|
|
@@ -40,6 +40,8 @@ const registrationUtils = require('./registrationUtils');
|
|
|
40
40
|
const subscriptions = require('../ngsi/subscriptionService');
|
|
41
41
|
const expressionPlugin = require('./../../plugins/expressionPlugin');
|
|
42
42
|
const pluginUtils = require('./../../plugins/pluginUtils');
|
|
43
|
+
const alarms = require('../common/alarmManagement');
|
|
44
|
+
const constants = require('../../constants');
|
|
43
45
|
const _ = require('underscore');
|
|
44
46
|
const context = {
|
|
45
47
|
op: 'IoTAgentNGSI.DeviceService'
|
|
@@ -250,7 +252,7 @@ function registerDevice(deviceObj, callback) {
|
|
|
250
252
|
/* eslint-disable-next-line no-unused-vars */
|
|
251
253
|
function (error, device) {
|
|
252
254
|
if (!error) {
|
|
253
|
-
innerCb(new errors.DuplicateDeviceId(deviceObj));
|
|
255
|
+
innerCb(new errors.DuplicateDeviceId(deviceObj), device);
|
|
254
256
|
} else {
|
|
255
257
|
innerCb();
|
|
256
258
|
}
|
|
@@ -664,7 +666,14 @@ function findOrCreate(deviceId, apikey, group, callback) {
|
|
|
664
666
|
if (group.autoprovision === undefined || group.autoprovision === true) {
|
|
665
667
|
logger.debug(context, 'Registering autoprovision of Device %j for its conf %j', newDevice, group);
|
|
666
668
|
registerDevice(newDevice, function (error, device) {
|
|
667
|
-
|
|
669
|
+
if (error && error.name === 'DUPLICATE_DEVICE_ID') {
|
|
670
|
+
alarms.release(constants.MONGO_ALARM, error);
|
|
671
|
+
logger.warn(context, 'Error %j already registered autoprovisioned device: %j ', error, device);
|
|
672
|
+
callback(null, device, group);
|
|
673
|
+
} else {
|
|
674
|
+
logger.debug(context, 'registered autoprovisioned device: %j ', device);
|
|
675
|
+
callback(error, device, group);
|
|
676
|
+
}
|
|
668
677
|
});
|
|
669
678
|
} else {
|
|
670
679
|
logger.info(
|
|
@@ -33,7 +33,6 @@ const logger = require('logops');
|
|
|
33
33
|
const config = require('../../commonConfig');
|
|
34
34
|
const ngsiLD = require('../ngsi/entities-NGSI-LD');
|
|
35
35
|
const utils = require('../northBound/restUtils');
|
|
36
|
-
const moment = require('moment');
|
|
37
36
|
const _ = require('underscore');
|
|
38
37
|
const registrationUtils = require('./registrationUtils');
|
|
39
38
|
const NGSIv2 = require('./devices-NGSI-v2');
|
|
@@ -153,7 +152,7 @@ function updateEntityNgsiLD(deviceData, updatedDevice, callback) {
|
|
|
153
152
|
) {
|
|
154
153
|
options.json[constants.TIMESTAMP_ATTRIBUTE] = {
|
|
155
154
|
type: constants.TIMESTAMP_TYPE_NGSI2,
|
|
156
|
-
value:
|
|
155
|
+
value: new Date().toISOString()
|
|
157
156
|
};
|
|
158
157
|
}
|
|
159
158
|
|
|
@@ -41,7 +41,6 @@ const registrationUtils = require('./registrationUtils');
|
|
|
41
41
|
const _ = require('underscore');
|
|
42
42
|
const utils = require('../northBound/restUtils');
|
|
43
43
|
const NGSIv2 = require('../ngsi/entities-NGSI-v2');
|
|
44
|
-
const moment = require('moment');
|
|
45
44
|
const context = {
|
|
46
45
|
op: 'IoTAgentNGSI.Devices-v2'
|
|
47
46
|
};
|
|
@@ -222,7 +221,7 @@ function updateEntityNgsi2(deviceData, updatedDevice, callback) {
|
|
|
222
221
|
) {
|
|
223
222
|
options.json[constants.TIMESTAMP_ATTRIBUTE] = {
|
|
224
223
|
type: constants.TIMESTAMP_TYPE_NGSI2,
|
|
225
|
-
value:
|
|
224
|
+
value: new Date().toISOString()
|
|
226
225
|
};
|
|
227
226
|
}
|
|
228
227
|
|
|
@@ -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 {
|
|
@@ -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);
|
|
@@ -292,9 +292,18 @@ function handleNotificationNgsi2(req, res, next) {
|
|
|
292
292
|
}
|
|
293
293
|
}
|
|
294
294
|
}
|
|
295
|
+
logger.debug(context, 'extracted atts %j from dataElement %j', atts, dataElement);
|
|
296
|
+
var id = null;
|
|
297
|
+
var type = null;
|
|
298
|
+
if (dataElement.targetEntityId && dataElement.targetEntityId.value) {
|
|
299
|
+
id = dataElement.targetEntityId.value;
|
|
300
|
+
}
|
|
301
|
+
if (dataElement.targetEntityType && dataElement.targetEntityType.value) {
|
|
302
|
+
type = dataElement.targetEntityType.value;
|
|
303
|
+
}
|
|
295
304
|
deviceService.getDeviceByNameAndType(
|
|
296
|
-
|
|
297
|
-
|
|
305
|
+
id,
|
|
306
|
+
type,
|
|
298
307
|
req.headers['fiware-service'],
|
|
299
308
|
req.headers['fiware-servicepath'],
|
|
300
309
|
function (error, device) {
|
|
@@ -336,7 +345,7 @@ function handleNotificationNgsi2(req, res, next) {
|
|
|
336
345
|
logger.error(context, 'Error found when processing notification: %j', error);
|
|
337
346
|
next(error);
|
|
338
347
|
} else {
|
|
339
|
-
res.status(
|
|
348
|
+
res.status(204).json();
|
|
340
349
|
}
|
|
341
350
|
}
|
|
342
351
|
|