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 +114 -59
- package/lib/errors.js +45 -20
- package/lib/services/commands/commandRegistryMemory.js +12 -2
- package/lib/services/commands/commandRegistryMongoDB.js +26 -15
- package/lib/services/devices/deviceRegistryMemory.js +1 -1
- package/lib/services/devices/deviceRegistryMongoDB.js +6 -4
- package/lib/services/devices/deviceService.js +3 -3
- package/lib/services/devices/devices-NGSI-LD.js +3 -3
- package/lib/services/devices/devices-NGSI-v2.js +10 -4
- package/lib/services/groups/groupRegistryMemory.js +1 -1
- package/lib/services/groups/groupRegistryMongoDB.js +1 -1
- package/lib/services/groups/groupService.js +9 -3
- package/lib/services/ngsi/entities-NGSI-LD.js +15 -7
- package/lib/services/ngsi/entities-NGSI-v2.js +20 -12
- package/lib/services/ngsi/ngsiService.js +3 -3
- package/lib/services/ngsi/subscription-NGSI-LD.js +2 -0
- package/lib/services/ngsi/subscription-NGSI-v2.js +2 -0
- package/lib/services/northBound/contextServer-NGSI-LD.js +50 -55
- package/lib/services/northBound/contextServer-NGSI-v2.js +1 -1
- package/lib/services/northBound/deviceProvisioningServer.js +100 -26
- package/lib/services/northBound/restUtils.js +1 -1
- package/package.json +1 -1
- package/test/functional/testCases.js +34 -34
- package/test/functional/testUtils.js +3 -1
- package/test/unit/ngsi-ld/ngsiService/active-devices-test.js +0 -1
- package/test/unit/ngsiv2/ngsiService/active-devices-test.js +8 -5
- package/test/unit/ngsiv2/provisioning/removeProvisionedDevice-test.js +37 -2
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
|
-
|
|
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
|
-
|
|
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
|
|
968
|
-
true
|
|
969
|
-
false
|
|
970
|
-
false
|
|
971
|
-
Not defined
|
|
972
|
-
Not defined
|
|
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
|
-
|
|
977
|
-
|
|
978
|
-
|
|
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
|
|
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
|
-
- `
|
|
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 =
|
|
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 =
|
|
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(
|
|
107
|
+
constructor(device) {
|
|
101
108
|
this.name = 'DUPLICATE_DEVICE_ID';
|
|
102
|
-
this.message =
|
|
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(
|
|
115
|
+
constructor(group) {
|
|
108
116
|
this.name = 'DUPLICATE_GROUP';
|
|
109
|
-
this.message =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
57
|
-
|
|
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(
|
|
128
|
-
|
|
129
|
-
results
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|