iotagent-node-lib 4.2.0 → 4.3.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/doc/api.md CHANGED
@@ -8,6 +8,7 @@
8
8
  - [IoT Agent information model](#iot-agent-information-model)
9
9
  - [Config groups](#config-groups)
10
10
  - [Devices](#devices)
11
+ - [Special measures and attributes names](#special-measures-and-attributes-names)
11
12
  - [Entity attributes](#entity-attributes)
12
13
  - [Multientity support)](#multientity-support)
13
14
  - [Metadata support](#metadata-support)
@@ -53,6 +54,8 @@
53
54
  - [Get device details `GET /iot/devices/:deviceId`](#get-device-details-get-iotdevicesdeviceid)
54
55
  - [Modify device `PUT /iot/devices/:deviceId`](#modify-device-put-iotdevicesdeviceid)
55
56
  - [Remove device `DELETE /iot/devices/:deviceId`](#remove-device-delete-iotdevicesdeviceid)
57
+ - [Batch Operations](#batch-operations)
58
+ - [Remove devices `POST /iot/op/delete`](#remove-devices-post-iotopdelete)
56
59
  - [Miscellaneous API](#miscellaneous-api)
57
60
  - [Log operations](#log-operations)
58
61
  - [Modify Loglevel `PUT /admin/log`](#modify-loglevel-put-adminlog)
@@ -149,6 +152,16 @@ This behavior allows that autoprovisioned parameters can freely established modi
149
152
  creation using the provisioning API. However, note that if a device (autoprovisioned or not) doesn't have these
150
153
  parameters defined at device level in database, the parameters are inherit from config group parameters.
151
154
 
155
+ ## Special measures and attributes names
156
+
157
+ In case of arriving measures with name `id` or `type`, they are automatically transformed to `measure_id` and
158
+ `measure_type` attributes at Context Broker update. The reason behind this is to avoid to collide with the original
159
+ entity ID and type, as mechanism that enable store measure values from parameters called with the same name. It only
160
+ applies to autoprovisioned attributes and is also available at JEXL context with the same name (`measure_id` or
161
+ `measure_type`).
162
+
163
+ In case of provisioning attributes using `id` or `type` as names (please don't do that ;), they are ignored.
164
+
152
165
  ## Entity attributes
153
166
 
154
167
  In the config group/device model there are four list of attributes with different purpose to configure how the
@@ -955,27 +968,27 @@ The IOTA processes the entity attributes looking for a `TimeInstant` attribute.
955
968
  adds a `TimeInstant` attribute as metadata for every other attribute in the same request. With NGSI-LD, the Standard
956
969
  `observedAt` property-of-a-property is used instead.
957
970
 
958
- If a `TimeInstant` arrives as measure but not follows [ISO_8601](https://en.wikipedia.org/wiki/ISO_8601) then measure
959
- is refused.
971
+ If a `TimeInstant` arrives as measure but not follows [ISO_8601](https://en.wikipedia.org/wiki/ISO_8601) then measure is
972
+ refused.
960
973
 
961
- Depending on the `timestamp` configuration and if the measure contains a
962
- value named `TimeInstant` with a correct value, the IoTA behaviour is described
963
- in the following table:
974
+ Depending on the `timestamp` configuration and if the measure contains a value named `TimeInstant` with a correct value,
975
+ the IoTA behaviour is described in the following table:
964
976
 
965
- `timestamp` value | measure contains `TimeInstant` | Behaviour
966
- -- | -- | --
967
- true | Yes | TimeInstant and metadata updated with measure value
968
- true | No | TimeInstant and metadata updated with server timestamp
969
- false | Yes | TimeInstant and metadata updated with measure value
970
- false | No | TimeInstant and metadata updated with server timestamp
971
- Not defined | Yes | TimeInstant and metadata updated with measure value
972
- Not defined | No | TimeInstant and metadata updated with server timestamp
977
+ | `timestamp` value | measure contains `TimeInstant` | Behaviour |
978
+ | ----------------- | ------------------------------ | ------------------------------------------------------ |
979
+ | true | Yes | TimeInstant and metadata updated with measure value |
980
+ | true | No | TimeInstant and metadata updated with server timestamp |
981
+ | false | Yes | TimeInstant and metadata updated with measure value |
982
+ | false | No | TimeInstant and metadata updated with server timestamp |
983
+ | Not defined | Yes | TimeInstant and metadata updated with measure value |
984
+ | Not defined | No | TimeInstant and metadata updated with server timestamp |
973
985
 
974
986
  The `timestamp` value used is:
975
987
 
976
- * The one defined at device level
977
- * The one defined at group level (if not defined at device level)
978
- * The one defined at [IoTA configuration level](admin.md#timestamp) / `IOTA_TIMESTAMP` env var (if not defined at group level or device level)
988
+ - The one defined at device level
989
+ - The one defined at group level (if not defined at device level)
990
+ - The one defined at [IoTA configuration level](admin.md#timestamp) / `IOTA_TIMESTAMP` env var (if not defined at
991
+ group level or device level)
979
992
 
980
993
  ## Overriding global Context Broker host
981
994
 
@@ -1217,29 +1230,29 @@ A `datasetId` is also maintained for each new attribute defined in the `reverse`
1217
1230
 
1218
1231
  Config group is represented by a JSON object with the following fields:
1219
1232
 
1220
- | Field | Optional | Type | Expression | Definitiom |
1221
- | ------------------------------ | -------- | -------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1222
- | `service` | | string | | `FIWARE-Service` header to be used |
1223
- | `subservice` | | string | | Subservice of the devices of this type. |
1224
- | `resource` | | string | | string representing the Southbound resource that will be used to assign a type to a device (e.g.: pathname in the southbound port). |
1225
- | `apikey` | | string | | API Key string. |
1233
+ | Field | Optional | Type | Expression | Definitiom |
1234
+ | ------------------------------ | -------- | -------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1235
+ | `service` | | string | | `FIWARE-Service` header to be used |
1236
+ | `subservice` | | string | | Subservice of the devices of this type. |
1237
+ | `resource` | | string | | string representing the Southbound resource that will be used to assign a type to a device (e.g.: pathname in the southbound port). |
1238
+ | `apikey` | | string | | API Key string. |
1226
1239
  | `timestamp` | ✓ | bool | | Optional flag about whether or not to add the `TimeInstant` attribute to the device entity created, as well as a `TimeInstant` metadata to each attribute, with the current server timestamp or provided `TimeInstant` as measure when follows ISO 8601 format (see [timestamp processing](#timestamp-processing) section for aditional detail). With NGSI-LD, the Standard `observedAt` property-of-a-property is created instead. |
1227
- | `entity_type` | | string | | name of the Entity `type` to assign to the group. |
1228
- | `trust` | ✓ | string | | trust token to use for secured access to the Context Broker for this type of devices (optional; only needed for secured scenarios). |
1229
- | `cbHost` | ✓ | string | | Context Broker connection information. This options can be used to override the global ones for specific types of devices. |
1230
- | `lazy` | ✓ | | | list of common lazy attributes of the device. For each attribute, its `name` and `type` must be provided. |
1231
- | `commands` | ✓ | | | list of common commands attributes of the device. For each attribute, its `name` and `type` must be provided, additional `metadata` is optional. |
1232
- | `attributes` | ✓ | | | list of common active attributes of the device. For each attribute, its `name` and `type` must be provided, additional `metadata` is optional. |
1233
- | `static_attributes` | ✓ | | | this attributes will be added to all the entities of this group 'as is', additional `metadata` is optional. |
1234
- | `internal_attributes` | ✓ | | | optional section with free format, to allow specific IoT Agents to store information along with the devices in the Device Registry. |
1235
- | `explicitAttrs` | ✓ | string or bool | ✓ | optional field to support selective ignore of measures so that IOTA doesn’t progress. See details in [specific section](#explicitly-defined-attributes-explicitattrs) |
1236
- | `entityNameExp` | ✓ | string | | optional field to allow use expressions to define entity name, instead default `id` and `type` |
1237
- | `ngsiVersion` | ✓ | string | | optional string value used in mixed mode to switch between **NGSI-v2** and **NGSI-LD** payloads. Possible values are: `v2` or `ld`. The default is `v2`. When not running in mixed mode, this field is ignored. |
1238
- | `defaultEntityNameConjunction` | ✓ | string | | optional string value to set default conjunction string used to compose a default `entity_name` when is not provided at device provisioning time. |
1239
- | `autoprovision` | ✓ | bool | ✓? | optional boolean: If `false`, autoprovisioned devices (i.e. devices that are not created with an explicit provision operation but when the first measure arrives) are not allowed in this group. Default (in the case of omitting the field) is `true`. |
1240
- | `payloadType` | ✓ | string | | optional string value used to switch between **IoTAgent**, **NGSI-v2** and **NGSI-LD** measure payloads types. Possible values are: `iotagent`, `ngsiv2` or `ngsild`. The default is `iotagent`. |
1241
- | `transport` | ✓ | `string` | | Transport protocol used by the group of devices to send updates, for the IoT Agents with multiple transport protocols. |
1242
- | `endpoint` | ✓ | `string` | | Endpoint where the group of device is going to receive commands, if any. |
1240
+ | `entity_type` | | string | | name of the Entity `type` to assign to the group. |
1241
+ | `trust` | ✓ | string | | trust token to use for secured access to the Context Broker for this type of devices (optional; only needed for secured scenarios). |
1242
+ | `cbHost` | ✓ | string | | Context Broker connection information. This options can be used to override the global ones for specific types of devices. |
1243
+ | `lazy` | ✓ | | | list of common lazy attributes of the device. For each attribute, its `name` and `type` must be provided. |
1244
+ | `commands` | ✓ | | | list of common commands attributes of the device. For each attribute, its `name` and `type` must be provided, additional `metadata` is optional. |
1245
+ | `attributes` | ✓ | | | list of common active attributes of the device. For each attribute, its `name` and `type` must be provided, additional `metadata` is optional. |
1246
+ | `static_attributes` | ✓ | | | this attributes will be added to all the entities of this group 'as is', additional `metadata` is optional. |
1247
+ | `internal_attributes` | ✓ | | | optional section with free format, to allow specific IoT Agents to store information along with the devices in the Device Registry. |
1248
+ | `explicitAttrs` | ✓ | string or bool | ✓ | optional field to support selective ignore of measures so that IOTA doesn’t progress. See details in [specific section](#explicitly-defined-attributes-explicitattrs) |
1249
+ | `entityNameExp` | ✓ | string | | optional field to allow use expressions to define entity name, instead default name, based on the device ID and the entity type (i.e. `<device_id>:<entity_type>`) |
1250
+ | `ngsiVersion` | ✓ | string | | optional string value used in mixed mode to switch between **NGSI-v2** and **NGSI-LD** payloads. Possible values are: `v2` or `ld`. The default is `v2`. When not running in mixed mode, this field is ignored. |
1251
+ | `defaultEntityNameConjunction` | ✓ | string | | optional string value to set default conjunction string used to compose a default `entity_name` when is not provided at device provisioning time. |
1252
+ | `autoprovision` | ✓ | bool | ✓? | optional boolean: If `false`, autoprovisioned devices (i.e. devices that are not created with an explicit provision operation but when the first measure arrives) are not allowed in this group. Default (in the case of omitting the field) is `true`. |
1253
+ | `payloadType` | ✓ | string | | optional string value used to switch between **IoTAgent**, **NGSI-v2** and **NGSI-LD** measure payloads types. Possible values are: `iotagent`, `ngsiv2` or `ngsild`. The default is `iotagent`. |
1254
+ | `transport` | ✓ | `string` | | Transport protocol used by the group of devices to send updates, for the IoT Agents with multiple transport protocols. |
1255
+ | `endpoint` | ✓ | `string` | | Endpoint where the group of device is going to receive commands, if any. |
1243
1256
 
1244
1257
  ### Config group operations
1245
1258
 
@@ -1439,27 +1452,27 @@ _**Response code**_
1439
1452
  The table below shows the information held in the Device resource. The table also contains the correspondence between
1440
1453
  the API resource fields and the same fields in the database model.
1441
1454
 
1442
- | Field | Optional | Type | Expression | Definitiom |
1443
- | --------------------- | -------- | --------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1444
- | `device_id` | | `string` | | Device ID that will be used to identify the device. |
1445
- | `service` | | `string` | | Name of the service the device belongs to (will be used in the fiware-service header). |
1446
- | `service_path` | | `string` | | Name of the subservice the device belongs to (used in the fiware-servicepath header). |
1447
- | `entity_name` | | `string` | | Name of the entity representing the device in the Context Broker |
1448
- | `entity_type` | | `string` | | Type of the entity in the Context Broker |
1449
- | `timezone` | ✓ | `string` | | Timezone of the device if that has any |
1455
+ | Field | Optional | Type | Expression | Definitiom |
1456
+ | --------------------- | -------- | --------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1457
+ | `device_id` | | `string` | | Device ID that will be used to identify the device. |
1458
+ | `service` | | `string` | | Name of the service the device belongs to (will be used in the fiware-service header). |
1459
+ | `service_path` | | `string` | | Name of the subservice the device belongs to (used in the fiware-servicepath header). |
1460
+ | `entity_name` | | `string` | | Name of the entity representing the device in the Context Broker |
1461
+ | `entity_type` | | `string` | | Type of the entity in the Context Broker |
1462
+ | `timezone` | ✓ | `string` | | Timezone of the device if that has any |
1450
1463
  | `timestamp` | ✓ | `string` | | Flag about whether or not to add the `TimeInstant` attribute to the device entity created, as well as a `TimeInstant` metadata to each attribute, with the current server timestamp or provided `TimeInstant` as measure when follows ISO 8601 format (see [timestamp processing](#timestamp-processing) section for aditional detail). With NGSI-LD, the Standard `observedAt` property-of-a-property is created instead. |
1451
- | `apikey` | ✓ | `string` | | Apikey key string to use instead of group apikey |
1452
- | `endpoint` | ✓ | `string` | | Endpoint where the device is going to receive commands, if any. |
1453
- | `protocol` | ✓ | `string` | | Pame of the device protocol, for its use with an IoT Manager |
1454
- | `transport` | ✓ | `string` | | Transport protocol used by the device to send updates, for the IoT Agents with multiple transport protocols. |
1455
- | `attributes` | ✓ | `array` | | List of attributes that will be stored in the Context Broker. |
1456
- | `commands` | ✓ | `array` | | List of commands that will be stored in the Context Broker. |
1457
- | `lazy` | ✓ | `array` | | List of lazy attributes that will be stored in the Context Broker. |
1458
- | `static_attributes` | ✓ | `array` | | List of static attributes that will be stored in the Context Broker. |
1459
- | `internal_attributes` | ✓ | `array` | | List of internal attributes with free format for specific IoT Agent configuration. |
1460
- | `explicitAttrs` | ✓ | `boolean` | ✓ | Field to support selective ignore of measures so that IOTA doesn’t progress. See details in [specific section](#explicitly-defined-attributes-explicitattrs) |
1461
- | `ngsiVersion` | ✓ | `string` | | string value used in mixed mode to switch between **NGSI-v2** and **NGSI-LD** payloads. The default is `v2`. When not running in mixed mode, this field is ignored. |
1462
- | `payloadType` | ✓ | `string` | | optional string value used to switch between **IoTAgent**, **NGSI-v2** and **NGSI-LD** measure payloads types. Possible values are: `iotagent`, `ngsiv2` or `ngsild`. The default is `iotagent`. |
1464
+ | `apikey` | ✓ | `string` | | Apikey key string to use instead of group apikey |
1465
+ | `endpoint` | ✓ | `string` | | Endpoint where the device is going to receive commands, if any. |
1466
+ | `protocol` | ✓ | `string` | | Pame of the device protocol, for its use with an IoT Manager |
1467
+ | `transport` | ✓ | `string` | | Transport protocol used by the device to send updates, for the IoT Agents with multiple transport protocols. |
1468
+ | `attributes` | ✓ | `array` | | List of attributes that will be stored in the Context Broker. |
1469
+ | `commands` | ✓ | `array` | | List of commands that will be stored in the Context Broker. |
1470
+ | `lazy` | ✓ | `array` | | List of lazy attributes that will be stored in the Context Broker. |
1471
+ | `static_attributes` | ✓ | `array` | | List of static attributes that will be stored in the Context Broker. |
1472
+ | `internal_attributes` | ✓ | `array` | | List of internal attributes with free format for specific IoT Agent configuration. |
1473
+ | `explicitAttrs` | ✓ | `boolean` | ✓ | Field to support selective ignore of measures so that IOTA doesn’t progress. See details in [specific section](#explicitly-defined-attributes-explicitattrs) |
1474
+ | `ngsiVersion` | ✓ | `string` | | string value used in mixed mode to switch between **NGSI-v2** and **NGSI-LD** payloads. The default is `v2`. When not running in mixed mode, this field is ignored. |
1475
+ | `payloadType` | ✓ | `string` | | optional string value used to switch between **IoTAgent**, **NGSI-v2** and **NGSI-LD** measure payloads types. Possible values are: `iotagent`, `ngsiv2` or `ngsild`. The default is `iotagent`. |
1463
1476
 
1464
1477
  ### Device operations
1465
1478
 
@@ -1710,10 +1723,52 @@ _**Request headers**_
1710
1723
 
1711
1724
  _**Response code**_
1712
1725
 
1713
- - `200` `OK` if successful.
1726
+ - `204` `OK` if successful.
1714
1727
  - `404` `NOT FOUND` if the device was not found in the database.
1715
1728
  - `500` `SERVER ERROR` if there was any error not contemplated above.
1716
1729
 
1730
+ ### Batch Operations
1731
+
1732
+ #### Remove devices `POST /iot/op/delete`
1733
+
1734
+ Remove a set of devices from the device registry. The devices is identified by the Device ID and apikey in payload body.
1735
+
1736
+ _**Request headers**_
1737
+
1738
+ | Header | Optional | Description | Example |
1739
+ | -------------------- | -------- | ---------------------------------------------------------------------------------------------- | ---------- |
1740
+ | `Fiware-Service` | ✓ | Tenant or service. See subsection [Multi tenancy](#multi-tenancy) for more information. | `acme` |
1741
+ | `Fiware-ServicePath` | ✓ | Service path or subservice. See subsection [Service Path](#service-path) for more information. | `/project` |
1742
+
1743
+ _**Request body**_
1744
+
1745
+ The request body contains an Array of objects which the values which identifies the devices, deviceId and apikey. For
1746
+ more information, see the [Device datamodel](#device-datamodel) section.
1747
+
1748
+ Example:
1749
+
1750
+ ```json
1751
+ {
1752
+ "devices": [
1753
+ {
1754
+ "deviceId": "myDevice1",
1755
+ "apikey": "apikey1"
1756
+ },
1757
+ {
1758
+ "deviceId": "myDevice2",
1759
+ "apikey": "apikey2"
1760
+ }
1761
+ ]
1762
+ }
1763
+ ```
1764
+
1765
+ _**Response code**_
1766
+
1767
+ - `204` `OK` if successful.
1768
+ - `404` `NOT FOUND` if one or several devices were not found in the database. Note that although a 404 error is
1769
+ returned the existing devices are deleted.
1770
+ - `500` `SERVER ERROR` if there was any error not considered above.
1771
+
1717
1772
  ## Miscellaneous API
1718
1773
 
1719
1774
  ### Log operations
package/lib/errors.js CHANGED
@@ -36,9 +36,15 @@ class UnregistrationError {
36
36
  }
37
37
  }
38
38
  class EntityGenericError {
39
- constructor(id, type, details, code) {
39
+ constructor(id, type, typeInformation, details, code) {
40
40
  this.name = 'ENTITY_GENERIC_ERROR';
41
- this.message = 'Error accesing entity data for device: ' + id + ' of type: ' + type;
41
+ this.message =
42
+ 'Error accesing entity data for device: ' +
43
+ id +
44
+ ' of type: ' +
45
+ type +
46
+ ' and ' +
47
+ JSON.stringify(typeInformation);
42
48
  this.details = details || {};
43
49
  this.code = code || 200;
44
50
  }
@@ -77,36 +83,44 @@ class UnsupportedContentType {
77
83
  }
78
84
  }
79
85
  class TypeNotFound {
80
- constructor(id, type) {
86
+ constructor(id, type, typeInformation) {
81
87
  this.name = 'TYPE_NOT_FOUND';
82
- this.message = 'Type : ' + type + ' not found for device with id: ' + id;
88
+ this.message =
89
+ 'Type : ' + type + ' not found for device with id: ' + id + ' with: ' + JSON.stringify(typeInformation);
83
90
  this.code = 500;
84
91
  }
85
92
  }
86
93
  class MissingAttributes {
87
- constructor(msg) {
94
+ constructor(msg, device) {
88
95
  this.name = 'MISSING_ATTRIBUTES';
89
- this.message = 'The request was not well formed:' + msg;
96
+ this.message = 'The request was not well formed:' + msg + ' with: ' + JSON.stringify(device);
90
97
  }
91
98
  }
92
99
  class DeviceNotFound {
93
- constructor(id) {
100
+ constructor(id, typeInformation) {
94
101
  this.name = 'DEVICE_NOT_FOUND';
95
- this.message = 'No device was found with id:' + id;
102
+ this.message = 'No device was found with id:' + id + ' and ' + JSON.stringify(typeInformation);
96
103
  this.code = 404;
97
104
  }
98
105
  }
99
106
  class DuplicateDeviceId {
100
- constructor(id) {
107
+ constructor(device) {
101
108
  this.name = 'DUPLICATE_DEVICE_ID';
102
- this.message = 'A device with the same pair (Service, DeviceId) was found:' + id;
109
+ this.message =
110
+ 'A device with the same pair (Service, DeviceId) was found:' + device.id + ' and ' + JSON.stringify(device);
103
111
  this.code = 409;
104
112
  }
105
113
  }
106
114
  class DuplicateGroup {
107
- constructor(res, key) {
115
+ constructor(group) {
108
116
  this.name = 'DUPLICATE_GROUP';
109
- this.message = 'A device configuration already exists for resource ' + res + ' and API Key ' + key;
117
+ this.message =
118
+ 'A device configuration already exists for resource ' +
119
+ group.resource +
120
+ ' and API Key ' +
121
+ group.apikey +
122
+ ' and ' +
123
+ JSON.stringify(group);
110
124
  this.code = 409;
111
125
  }
112
126
  }
@@ -170,9 +184,13 @@ class WrongSyntax {
170
184
  }
171
185
  }
172
186
  class CommandNotFound {
173
- constructor(name) {
187
+ constructor(name, typeInformation) {
174
188
  this.name = 'COMMAND_NOT_FOUND';
175
- this.message = "Couldn't update the command because no command with the name [" + name + '] was found.';
189
+ this.message =
190
+ "Couldn't update the command because no command with the name [" +
191
+ name +
192
+ '] was found with ' +
193
+ JSON.stringify(typeInformation);
176
194
  this.code = 400;
177
195
  }
178
196
  }
@@ -201,9 +219,10 @@ class DeviceGroupNotFound {
201
219
  }
202
220
  }
203
221
  class GroupNotFound {
204
- constructor(service, subservice) {
222
+ constructor(service, subservice, type) {
205
223
  this.name = 'GROUP_NOT_FOUND';
206
- this.message = 'Group not found for service [' + service + '] and subservice [' + subservice + ']';
224
+ this.message =
225
+ 'Group not found for service [' + service + '] subservice [' + subservice + '] and type [' + type + ']';
207
226
  this.code = 404;
208
227
  }
209
228
  }
@@ -229,16 +248,22 @@ class BadAnswer {
229
248
  }
230
249
  }
231
250
  class BadTimestamp {
232
- constructor(payload, entityName) {
251
+ constructor(payload, entityName, typeInformation) {
233
252
  this.name = 'BAD_TIMESTAMP';
234
- this.message = 'Invalid ISO8601 timestamp [' + payload + '] in [' + entityName + ']';
253
+ this.message =
254
+ 'Invalid ISO8601 timestamp [' +
255
+ payload +
256
+ '] in [' +
257
+ entityName +
258
+ '] with: ' +
259
+ JSON.stringify(typeInformation);
235
260
  this.code = 400;
236
261
  }
237
262
  }
238
263
  class BadGeocoordinates {
239
- constructor(payload) {
264
+ constructor(payload, device) {
240
265
  this.name = 'BAD_GEOCOORDINATES';
241
- this.message = 'Invalid rfc7946 coordinates [' + payload + ']';
266
+ this.message = 'Invalid rfc7946 coordinates [' + payload + '] in ' + JSON.stringify(device);
242
267
  this.code = 400;
243
268
  }
244
269
  }
@@ -75,7 +75,12 @@ function updateCommand(service, subservice, deviceId, command, callback) {
75
75
 
76
76
  callback(null, foundCommand);
77
77
  } else {
78
- callback(new errors.CommandNotFound(command.name));
78
+ const deviceInfo = {
79
+ service,
80
+ subservice,
81
+ deviceId
82
+ };
83
+ callback(new errors.CommandNotFound(command.name, deviceInfo));
79
84
  }
80
85
  }
81
86
 
@@ -144,7 +149,12 @@ function remove(service, subservice, deviceId, name, callback) {
144
149
  delete registeredCommands[foundCommand._id];
145
150
  callback(null, foundCommand);
146
151
  } else {
147
- callback(new errors.CommandNotFound(name));
152
+ const deviceInfo = {
153
+ service,
154
+ subservice,
155
+ deviceId
156
+ };
157
+ callback(new errors.CommandNotFound(name, deviceInfo));
148
158
  }
149
159
  }
150
160
 
@@ -39,7 +39,7 @@ function findCommand(service, subservice, deviceId, name, callback) {
39
39
  name
40
40
  };
41
41
 
42
- logger.debug(context, 'Looking for command [%s] for device [%s]', name, deviceId);
42
+ logger.debug(context, 'Looking for command [%s] for device [%s] with [%j]', name, deviceId, queryObj);
43
43
 
44
44
  const query = Command.model.findOne(queryObj);
45
45
 
@@ -53,8 +53,14 @@ function findCommand(service, subservice, deviceId, name, callback) {
53
53
  } else if (data) {
54
54
  callback(null, data);
55
55
  } else {
56
- logger.debug(context, 'Command for DeviceID [%j] with name [%j] not found', deviceId, name);
57
- callback(new errors.CommandNotFound(name));
56
+ logger.debug(
57
+ context,
58
+ 'Command for DeviceID [%j] with name [%j] not found with [%j]',
59
+ deviceId,
60
+ name,
61
+ queryObj
62
+ );
63
+ callback(new errors.CommandNotFound(name, queryObj));
58
64
  }
59
65
  });
60
66
  }
@@ -124,15 +130,15 @@ function listCommands(service, subservice, deviceId, callback) {
124
130
 
125
131
  const query = Command.model.find(condition).sort();
126
132
 
127
- async.series([query.exec.bind(query), Command.model.countDocuments.bind(Command.model, condition)], function (
128
- error,
129
- results
130
- ) {
131
- callback(error, {
132
- count: results[1],
133
- commands: results[0].map(toObjectFn)
134
- });
135
- });
133
+ async.series(
134
+ [query.exec.bind(query), Command.model.countDocuments.bind(Command.model, condition)],
135
+ function (error, results) {
136
+ callback(error, {
137
+ count: results[1],
138
+ commands: results[0].map(toObjectFn)
139
+ });
140
+ }
141
+ );
136
142
  }
137
143
 
138
144
  function remove(service, subservice, deviceId, name, callback) {
@@ -159,9 +165,14 @@ function remove(service, subservice, deviceId, name, callback) {
159
165
 
160
166
  callback(null, commandResult);
161
167
  } else {
162
- logger.debug(context, 'Command [%s] not found for removal.', name);
163
-
164
- callback(new errors.CommandNotFound(name));
168
+ const deviceInfo = {
169
+ service,
170
+ subservice,
171
+ deviceId,
172
+ name
173
+ };
174
+ logger.debug(context, 'Command [%s] not found for removal with %j', name, deviceInfo);
175
+ callback(new errors.CommandNotFound(name, deviceInfo));
165
176
  }
166
177
  });
167
178
  }
@@ -54,7 +54,7 @@ function storeDevice(newDevice, callback) {
54
54
  }
55
55
 
56
56
  if (registeredDevices[newDevice.service][newDevice.id]) {
57
- callback(new errors.DuplicateDeviceId(newDevice.id));
57
+ callback(new errors.DuplicateDeviceId(newDevice));
58
58
  } else {
59
59
  registeredDevices[newDevice.service][newDevice.id] = deepClone(newDevice);
60
60
  registeredDevices[newDevice.service][newDevice.id].creationDate = Date.now();
@@ -56,6 +56,7 @@ const attributeList = [
56
56
  'timestamp',
57
57
  'explicitAttrs',
58
58
  'ngsiVersion',
59
+ 'subscriptions',
59
60
  'payloadType'
60
61
  ];
61
62
 
@@ -101,7 +102,7 @@ function storeDevice(newDevice, callback) {
101
102
  if (error.code === 11000) {
102
103
  logger.debug(context, 'Tried to insert a device with duplicate ID in the database: %s', error);
103
104
 
104
- callback(new errors.DuplicateDeviceId(newDevice.id));
105
+ callback(new errors.DuplicateDeviceId(newDevice));
105
106
  } else {
106
107
  logger.debug(context, 'Error storing device information: %s', error);
107
108
 
@@ -205,7 +206,7 @@ function findOneInMongoDB(queryParams, id, callback) {
205
206
  } else {
206
207
  logger.debug(context, 'Device [%s] not found.', id);
207
208
 
208
- callback(new errors.DeviceNotFound(id));
209
+ callback(new errors.DeviceNotFound(id, queryParams));
209
210
  }
210
211
  });
211
212
  }
@@ -281,7 +282,7 @@ function getByNameAndType(name, type, service, servicepath, callback) {
281
282
  } else {
282
283
  logger.debug(context, 'Device [%s] not found.', name);
283
284
 
284
- callback(new errors.DeviceNotFound(name));
285
+ callback(new errors.DeviceNotFound(name, optionsQuery));
285
286
  }
286
287
  });
287
288
  }
@@ -318,6 +319,7 @@ function update(device, callback) {
318
319
  data.explicitAttrs = device.explicitAttrs;
319
320
  data.ngsiVersion = device.ngsiVersion;
320
321
  data.timestamp = device.timestamp;
322
+ data.subscriptions = device.subscriptions;
321
323
  data.payloadType = device.payloadType;
322
324
 
323
325
  /* eslint-disable-next-line new-cap */
@@ -371,7 +373,7 @@ function getDevicesByAttribute(name, value, service, subservice, callback) {
371
373
  } else {
372
374
  logger.debug(context, 'Device [%s] not found.', name);
373
375
 
374
- callback(new errors.DeviceNotFound(name));
376
+ callback(new errors.DeviceNotFound(name, filter));
375
377
  }
376
378
  });
377
379
  }
@@ -244,7 +244,7 @@ function registerDevice(deviceObj, callback) {
244
244
  /* eslint-disable-next-line no-unused-vars */
245
245
  function (error, device) {
246
246
  if (!error) {
247
- innerCb(new errors.DuplicateDeviceId(deviceObj.id));
247
+ innerCb(new errors.DuplicateDeviceId(deviceObj));
248
248
  } else {
249
249
  innerCb();
250
250
  }
@@ -646,7 +646,7 @@ function findOrCreate(deviceId, apikey, group, callback) {
646
646
  newDevice,
647
647
  group
648
648
  );
649
- callback(new errors.DeviceNotFound(deviceId));
649
+ callback(new errors.DeviceNotFound(deviceId, newDevice));
650
650
  }
651
651
  } else {
652
652
  callback(error);
@@ -671,7 +671,7 @@ function retrieveDevice(deviceId, apiKey, callback) {
671
671
  } else {
672
672
  logger.error(context, "Couldn't find device data for APIKey [%s] and DeviceId[%s]", deviceId, apiKey);
673
673
 
674
- callback(new errors.DeviceNotFound(deviceId));
674
+ callback(new errors.DeviceNotFound(deviceId, { apikey: apiKey }));
675
675
  }
676
676
  });
677
677
  } else {
@@ -93,7 +93,7 @@ function updateEntityHandlerNgsiLD(deviceData, updatedDevice, callback) {
93
93
  body
94
94
  );
95
95
 
96
- const errorObj = new errors.EntityGenericError(deviceData.id, deviceData.type, body);
96
+ const errorObj = new errors.EntityGenericError(deviceData.id, deviceData.type, deviceData, body);
97
97
 
98
98
  callback(errorObj);
99
99
  }
@@ -184,7 +184,7 @@ function updateEntityNgsiLD(deviceData, updatedDevice, callback) {
184
184
  */
185
185
  function updateRegisterDeviceNgsiLD(deviceObj, entityInfoUpdated, callback) {
186
186
  if (!deviceObj.id || !deviceObj.type) {
187
- callback(new errors.MissingAttributes('Id or device missing'));
187
+ callback(new errors.MissingAttributes('Id or device missing', deviceObj));
188
188
  return;
189
189
  }
190
190
 
@@ -216,7 +216,7 @@ function updateRegisterDeviceNgsiLD(deviceObj, entityInfoUpdated, callback) {
216
216
 
217
217
  callback(null, oldDevice);
218
218
  } else {
219
- callback(new errors.DeviceNotFound(newDevice.id));
219
+ callback(new errors.DeviceNotFound(newDevice.id, newDevice));
220
220
  }
221
221
  }
222
222