iotagent-node-lib 4.1.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.
Files changed (31) hide show
  1. package/.readthedocs.yml +5 -1
  2. package/CHANGES_NEXT_RELEASE +0 -1
  3. package/doc/api.md +125 -50
  4. package/doc/requirements.txt +2 -2
  5. package/lib/constants.js +2 -1
  6. package/lib/errors.js +45 -20
  7. package/lib/services/commands/commandRegistryMemory.js +12 -2
  8. package/lib/services/commands/commandRegistryMongoDB.js +26 -15
  9. package/lib/services/devices/deviceRegistryMemory.js +1 -1
  10. package/lib/services/devices/deviceRegistryMongoDB.js +6 -4
  11. package/lib/services/devices/deviceService.js +3 -3
  12. package/lib/services/devices/devices-NGSI-LD.js +3 -3
  13. package/lib/services/devices/devices-NGSI-v2.js +10 -4
  14. package/lib/services/groups/groupRegistryMemory.js +1 -1
  15. package/lib/services/groups/groupRegistryMongoDB.js +1 -1
  16. package/lib/services/groups/groupService.js +9 -3
  17. package/lib/services/ngsi/entities-NGSI-LD.js +15 -7
  18. package/lib/services/ngsi/entities-NGSI-v2.js +26 -13
  19. package/lib/services/ngsi/ngsiService.js +3 -3
  20. package/lib/services/ngsi/subscription-NGSI-LD.js +2 -0
  21. package/lib/services/ngsi/subscription-NGSI-v2.js +2 -0
  22. package/lib/services/northBound/contextServer-NGSI-LD.js +50 -55
  23. package/lib/services/northBound/contextServer-NGSI-v2.js +1 -1
  24. package/lib/services/northBound/deviceProvisioningServer.js +100 -26
  25. package/lib/services/northBound/restUtils.js +1 -1
  26. package/package.json +1 -1
  27. package/test/functional/testCases.js +34 -34
  28. package/test/functional/testUtils.js +3 -1
  29. package/test/unit/ngsi-ld/ngsiService/active-devices-test.js +0 -1
  30. package/test/unit/ngsiv2/ngsiService/active-devices-test.js +22 -3
  31. package/test/unit/ngsiv2/provisioning/removeProvisionedDevice-test.js +37 -2
package/.readthedocs.yml CHANGED
@@ -3,7 +3,11 @@ version: 2
3
3
  mkdocs:
4
4
  configuration: mkdocs.yml
5
5
 
6
+ build:
7
+ os: ubuntu-22.04
8
+ tools:
9
+ python: "3.8"
10
+
6
11
  python:
7
- version: 3.8
8
12
  install:
9
13
  - requirements: doc/requirements.txt
@@ -1 +0,0 @@
1
-
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,6 +968,28 @@ 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
 
971
+ If a `TimeInstant` arrives as measure but not follows [ISO_8601](https://en.wikipedia.org/wiki/ISO_8601) then measure is
972
+ refused.
973
+
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:
976
+
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 |
985
+
986
+ The `timestamp` value used is:
987
+
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)
992
+
958
993
  ## Overriding global Context Broker host
959
994
 
960
995
  **cbHost**: Context Broker host URL. This option can be used to override the global CB configuration for specific types
@@ -963,8 +998,7 @@ of devices.
963
998
  ## Multitenancy, FIWARE Service and FIWARE ServicePath
964
999
 
965
1000
  Every operation in the API require the `fiware-service` and `fiware-servicepath` to be defined; the operations are
966
- performed in the scope of those headers. For the list case, the special wildcard servicepath can be specified, `/*`. In
967
- this case, the operation applies to all the subservices of the service given by the `fiware-service` header.
1001
+ performed in the scope of those headers.
968
1002
 
969
1003
  ## Secured access to the Context Broker
970
1004
 
@@ -1196,29 +1230,29 @@ A `datasetId` is also maintained for each new attribute defined in the `reverse`
1196
1230
 
1197
1231
  Config group is represented by a JSON object with the following fields:
1198
1232
 
1199
- | Field | Optional | Type | Expression | Definitiom |
1200
- | ------------------------------ | -------- | -------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1201
- | `service` | | string | | `FIWARE-Service` header to be used |
1202
- | `subservice` | | string | | Subservice of the devices of this type. |
1203
- | `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). |
1204
- | `apikey` | | string | | API Key string. |
1205
- | `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 timestamp. With NGSI-LD, the Standard `observedAt` property-of-a-property is created instead. |
1206
- | `entity_type` | | string | | name of the Entity `type` to assign to the group. |
1207
- | `trust` | ✓ | string | | trust token to use for secured access to the Context Broker for this type of devices (optional; only needed for secured scenarios). |
1208
- | `cbHost` | ✓ | string | | Context Broker connection information. This options can be used to override the global ones for specific types of devices. |
1209
- | `lazy` | ✓ | | | list of common lazy attributes of the device. For each attribute, its `name` and `type` must be provided. |
1210
- | `commands` | ✓ | | | list of common commands attributes of the device. For each attribute, its `name` and `type` must be provided, additional `metadata` is optional. |
1211
- | `attributes` | ✓ | | | list of common active attributes of the device. For each attribute, its `name` and `type` must be provided, additional `metadata` is optional. |
1212
- | `static_attributes` | ✓ | | | this attributes will be added to all the entities of this group 'as is', additional `metadata` is optional. |
1213
- | `internal_attributes` | ✓ | | | optional section with free format, to allow specific IoT Agents to store information along with the devices in the Device Registry. |
1214
- | `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) |
1215
- | `entityNameExp` | ✓ | string | | optional field to allow use expressions to define entity name, instead default `id` and `type` |
1216
- | `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. |
1217
- | `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. |
1218
- | `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`. |
1219
- | `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`. |
1220
- | `transport` | ✓ | `string` | | Transport protocol used by the group of devices to send updates, for the IoT Agents with multiple transport protocols. |
1221
- | `endpoint` | ✓ | `string` | | Endpoint where the group of device is going to receive commands, if any. |
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. |
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. |
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. |
1222
1256
 
1223
1257
  ### Config group operations
1224
1258
 
@@ -1226,9 +1260,8 @@ The following actions are available under the config group endpoint:
1226
1260
 
1227
1261
  #### Retrieve config groups `GET /iot/services`
1228
1262
 
1229
- List all the config groups for the given `fiware-service` and `fiware-servicepath`. If the `fiware-servicepath` header
1230
- has the wildcard expression, `/*`, all the config groups for that `fiware-service` are returned. The config groups that
1231
- match the `fiware-servicepath` are returned in any other case.
1263
+ List all the config groups for the given `fiware-service` and `fiware-servicepath`. The config groups that match the
1264
+ `fiware-servicepath` are returned in any other case.
1232
1265
 
1233
1266
  _**Request headers**_
1234
1267
 
@@ -1419,27 +1452,27 @@ _**Response code**_
1419
1452
  The table below shows the information held in the Device resource. The table also contains the correspondence between
1420
1453
  the API resource fields and the same fields in the database model.
1421
1454
 
1422
- | Field | Optional | Type | Expression | Definitiom |
1423
- | --------------------- | -------- | --------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1424
- | `device_id` | | `string` | | Device ID that will be used to identify the device. |
1425
- | `service` | | `string` | | Name of the service the device belongs to (will be used in the fiware-service header). |
1426
- | `service_path` | | `string` | | Name of the subservice the device belongs to (used in the fiware-servicepath header). |
1427
- | `entity_name` | | `string` | | Name of the entity representing the device in the Context Broker |
1428
- | `entity_type` | | `string` | | Type of the entity in the Context Broker |
1429
- | `timezone` | ✓ | `string` | | Timezone of the device if that has any |
1430
- | `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 timestamp. With NGSI-LD, the Standard `observedAt` property-of-a-property is created instead. |
1431
- | `apikey` | ✓ | `string` | | Apikey key string to use instead of group apikey |
1432
- | `endpoint` | ✓ | `string` | | Endpoint where the device is going to receive commands, if any. |
1433
- | `protocol` | ✓ | `string` | | Pame of the device protocol, for its use with an IoT Manager |
1434
- | `transport` | ✓ | `string` | | Transport protocol used by the device to send updates, for the IoT Agents with multiple transport protocols. |
1435
- | `attributes` | ✓ | `array` | | List of attributes that will be stored in the Context Broker. |
1436
- | `commands` | ✓ | `array` | | List of commands that will be stored in the Context Broker. |
1437
- | `lazy` | ✓ | `array` | | List of lazy attributes that will be stored in the Context Broker. |
1438
- | `static_attributes` | ✓ | `array` | | List of static attributes that will be stored in the Context Broker. |
1439
- | `internal_attributes` | ✓ | `array` | | List of internal attributes with free format for specific IoT Agent configuration. |
1440
- | `explicitAttrs` | ✓ | `boolean` | ✓ | Field to support selective ignore of measures so that IOTA doesn’t progress. See details in [specific section](#explicitly-defined-attributes-explicitattrs) |
1441
- | `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. |
1442
- | `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`. |
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 |
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. |
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`. |
1443
1476
 
1444
1477
  ### Device operations
1445
1478
 
@@ -1690,10 +1723,52 @@ _**Request headers**_
1690
1723
 
1691
1724
  _**Response code**_
1692
1725
 
1693
- - `200` `OK` if successful.
1726
+ - `204` `OK` if successful.
1694
1727
  - `404` `NOT FOUND` if the device was not found in the database.
1695
1728
  - `500` `SERVER ERROR` if there was any error not contemplated above.
1696
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
+
1697
1772
  ## Miscellaneous API
1698
1773
 
1699
1774
  ### Log operations
@@ -1,4 +1,4 @@
1
- mkdocs==1.2.3
1
+ mkdocs==1.2.4
2
2
  Pygments==2.15.0
3
3
  Markdown==3.3.4
4
- jinja2==3.0.0
4
+ jinja2==3.1.3
package/lib/constants.js CHANGED
@@ -61,6 +61,7 @@ module.exports = {
61
61
  NGSI_LD_TENANT_HEADER: 'NGSILD-Tenant',
62
62
  NGSI_LD_PATH_HEADER: 'NGSILD-Path',
63
63
  NGSI_LD_NULL: 'urn:ngsi-ld:null',
64
+ MEASURE: 'measure_',
64
65
  //FIXME: check Keystone support this in lowercase, then change
65
66
  AUTH_HEADER: 'X-Auth-Token',
66
67
  X_FORWARDED_FOR_HEADER: 'x-forwarded-for',
@@ -83,7 +84,7 @@ module.exports = {
83
84
  MONGO_ALARM: 'MONGO-ALARM',
84
85
  ORION_ALARM: 'ORION-ALARM',
85
86
  IOTAM_ALARM: 'IOTAM-ALARM',
86
-
87
+
87
88
  ATTRIBUTE_DEFAULT,
88
89
  DATETIME_DEFAULT,
89
90
 
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
  }