iotagent-node-lib 4.4.0 → 4.6.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/README.md +67 -272
- package/config.js +2 -1
- package/doc/README.md +1 -1
- package/doc/admin.md +19 -22
- package/doc/api.md +621 -155
- package/doc/deprecated.md +4 -0
- package/doc/devel/architecture.md +5 -135
- package/doc/devel/development.md +224 -12
- package/doc/getting-started.md +114 -53
- package/doc/requirements.txt +1 -1
- package/doc/roadmap.md +5 -5
- package/docker/Mosquitto/Dockerfile +2 -2
- package/docker/Mosquitto/README.md +14 -11
- package/lib/commonConfig.js +7 -1
- package/lib/constants.js +3 -0
- package/lib/fiware-iotagent-lib.js +12 -15
- package/lib/jexlTranformsMap.js +3 -1
- package/lib/model/dbConn.js +1 -4
- package/lib/services/common/alarmManagement.js +3 -0
- package/lib/services/devices/deviceRegistryMemory.js +1 -1
- package/lib/services/devices/deviceRegistryMongoDB.js +2 -2
- package/lib/services/devices/deviceService.js +4 -3
- package/lib/services/devices/devices-NGSI-LD.js +5 -5
- package/lib/services/devices/devices-NGSI-mixed.js +3 -3
- package/lib/services/devices/devices-NGSI-v2.js +5 -5
- package/lib/services/groups/groupService.js +1 -1
- package/lib/services/ngsi/entities-NGSI-LD.js +321 -571
- package/lib/services/ngsi/entities-NGSI-v2.js +348 -281
- package/lib/services/ngsi/ngsiService.js +3 -1
- package/lib/services/ngsi/subscription-NGSI-LD.js +2 -2
- package/lib/services/ngsi/subscription-NGSI-v2.js +2 -2
- package/lib/services/northBound/deviceGroupAdministrationServer.js +42 -6
- package/lib/services/northBound/deviceProvisioningServer.js +5 -5
- package/lib/services/northBound/northboundServer.js +4 -2
- package/lib/services/stats/statsRegistry.js +128 -101
- package/lib/templates/createDevice.json +0 -24
- package/lib/templates/createDeviceLax.json +0 -23
- package/lib/templates/deviceGroup.json +1 -25
- package/lib/templates/updateDevice.json +0 -24
- package/lib/templates/updateDeviceLax.json +0 -23
- package/package.json +2 -2
- package/scripts/legacy_expression_tool/README.md +0 -1
- package/test/functional/README.md +75 -47
- package/test/functional/functional-tests-runner.js +9 -4
- package/test/functional/functional-tests.js +4 -4
- package/test/functional/testCases.js +1251 -257
- package/test/functional/testUtils.js +53 -20
- package/test/unit/examples/deviceProvisioningRequests/provisionFullDevice.json +1 -13
- package/test/unit/examples/deviceProvisioningRequests/updateProvisionDeviceWithApikey.json +4 -0
- package/test/unit/examples/groupProvisioningRequests/multipleConfigGroupsCreation.json +44 -0
- package/test/unit/examples/groupProvisioningRequests/provisionDuplicateConfigGroup.json +35 -0
- package/test/unit/examples/groupProvisioningRequests/provisionFullConfigGroup.json +36 -0
- package/test/unit/examples/groupProvisioningRequests/provisionFullConfigGroupAlternate.json +36 -0
- package/test/unit/general/deviceService-test.js +102 -0
- package/test/unit/general/statistics-service_test.js +1 -74
- package/test/unit/mongodb/mongodb-configGroup-registry-test.js +452 -0
- package/test/unit/mongodb/mongodb-connectionoptions-test.js +2 -3
- package/test/unit/mongodb/mongodb-group-registry-test.js +34 -33
- package/test/unit/mongodb/mongodb-service-registry-test.js +477 -0
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin1a.json +4 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin2.json +22 -22
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin29.json +4 -4
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin32.json +14 -15
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin1.json +23 -23
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin15.json +0 -5
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin4.json +11 -16
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin5.json +23 -28
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin6.json +8 -13
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin7.json +0 -5
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin8.json +24 -29
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityTimestampPlugin2.json +12 -17
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextStaticLinkedAttributes.json +12 -10
- package/test/unit/ngsi-ld/expressions/jexlBasedTransformations-test.js +0 -102
- package/test/unit/ngsi-ld/plugins/multientity-plugin_test.js +4 -5
- package/test/unit/ngsi-ld/provisioning/device-update-registration_test.js +5 -5
- package/test/unit/ngsi-ld/provisioning/listProvisionedDevices-test.js +0 -4
- package/test/unit/ngsiv2/general/deviceService-test.js +94 -1
- package/test/unit/ngsiv2/general/iotam-autoregistration-test.js +195 -0
- package/test/unit/ngsiv2/provisioning/device-group-api-test.js +259 -0
- package/test/unit/ngsiv2/provisioning/device-provisioning-configGroup-api_test.js +1189 -0
- package/test/unit/ngsiv2/provisioning/device-update-registration_test.js +6 -6
- package/test/unit/ngsiv2/provisioning/listProvisionedDevices-test.js +0 -4
- package/test/unit/ngsiv2/provisioning/updateProvisionedDevices-test.js +35 -0
- package/test/unit/statsRegistry/openmetrics-test.js +167 -0
- package/lib/templates/queryContext.json +0 -25
- package/test/unit/examples/deviceProvisioningRequests/provisionBidirectionalDevice.json +0 -35
- package/test/unit/examples/deviceProvisioningRequests/provisionDeviceBidirectionalGroup.json +0 -17
- package/test/unit/examples/groupProvisioningRequests/bidirectionalGroup.json +0 -31
- package/test/unit/general/statistics-persistence_test.js +0 -121
- package/test/unit/ngsi-ld/examples/contextRequests/createBidirectionalDevice.json +0 -17
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextProcessTimestamp.json +0 -12
- package/test/unit/ngsi-ld/examples/subscriptionRequests/bidirectionalNotification.json +0 -13
- package/test/unit/ngsi-ld/examples/subscriptionRequests/bidirectionalNotificationWithDatasetId.json +0 -21
- package/test/unit/ngsi-ld/examples/subscriptionRequests/bidirectionalNotificationWithMetadata.json +0 -17
- package/test/unit/ngsi-ld/examples/subscriptionRequests/bidirectionalSubscriptionRequest.json +0 -23
- package/test/unit/ngsi-ld/plugins/timestamp-processing-plugin_test.js +0 -132
- package/test/unit/ngsiv2/examples/contextRequests/createBidirectionalDevice.json +0 -8
- package/test/unit/ngsiv2/examples/subscriptionRequests/bidirectionalNotification.json +0 -13
- package/test/unit/ngsiv2/examples/subscriptionRequests/bidirectionalNotificationWithMetadata.json +0 -19
- package/test/unit/ngsiv2/examples/subscriptionRequests/bidirectionalSubscriptionRequest.json +0 -24
package/doc/getting-started.md
CHANGED
|
@@ -1,64 +1,92 @@
|
|
|
1
|
-
|
|
1
|
+
# Getting Started
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
- [Introduction](#introduction)
|
|
4
|
+
- [IoT Agent settings - `config.js`](#iot-agent-settings---configjs)
|
|
5
|
+
- [Provisioning a Config Group](#provisioning-a-config-group)
|
|
6
|
+
- [Provisioning an Individual Device](#provisioning-an-individual-device)
|
|
7
|
+
- [Receiving measures from devices](#receiving-measures-from-devices)
|
|
8
|
+
- [Receiving a measure from a known Device](#receiving-a-measure-from-a-known-device)
|
|
9
|
+
- [Receiving a measure from an anonymous Device](#receiving-a-measure-from-an-anonymous-device)
|
|
5
10
|
|
|
6
|
-
|
|
11
|
+
## Introduction
|
|
12
|
+
|
|
13
|
+
In this guide we will be using the IoT Agent JSON (which is the reference IoTAgent using the IoTAgent Library) as an
|
|
14
|
+
example to demonstrate how to provision config groups, devices and how to receive measures from devices.
|
|
15
|
+
|
|
16
|
+
Be aware that every IoT Agent which uses the library is different, but the concepts for provisioning IoT devices remain
|
|
17
|
+
the same regardless of protocol.
|
|
18
|
+
|
|
19
|
+
The IoT Agent JSON is a simple IoT Agent which uses JSON payloads to send and receive data. It is a good starting point
|
|
20
|
+
for understanding how an IoT Agent works since it uses JSON payloads to send and receive data.
|
|
21
|
+
|
|
22
|
+
## IoT Agent settings - `config.js`
|
|
7
23
|
|
|
8
24
|
The `config.js` holds common information about the interactions between the Agent and the Context Broker. Additional
|
|
9
|
-
custom settings may also be required dependent upon the actual IoT Agent used.
|
|
25
|
+
custom settings may also be required dependent upon the actual IoT Agent used. The following is an example of a typical
|
|
26
|
+
`config.js` file:
|
|
10
27
|
|
|
11
28
|
```javascript
|
|
12
29
|
config = {
|
|
13
|
-
logLevel:
|
|
30
|
+
logLevel: 'DEBUG',
|
|
14
31
|
contextBroker: {
|
|
15
|
-
host:
|
|
16
|
-
port:
|
|
32
|
+
host: 'orion',
|
|
33
|
+
port: '1026'
|
|
17
34
|
},
|
|
18
35
|
server: {
|
|
19
36
|
port: 4041,
|
|
20
|
-
host:
|
|
37
|
+
host: '0.0.0.0'
|
|
21
38
|
},
|
|
22
39
|
deviceRegistry: {
|
|
23
|
-
type:
|
|
40
|
+
type: 'mongodb'
|
|
41
|
+
},
|
|
42
|
+
mongodb: {
|
|
43
|
+
host: 'localhost',
|
|
44
|
+
port: '27017',
|
|
45
|
+
db: 'iotagent'
|
|
24
46
|
},
|
|
25
|
-
service:
|
|
26
|
-
subservice:
|
|
27
|
-
providerUrl:
|
|
28
|
-
defaultType:
|
|
47
|
+
service: 'openiot',
|
|
48
|
+
subservice: '/',
|
|
49
|
+
providerUrl: 'http://iot-agent:4041',
|
|
50
|
+
defaultType: 'Thing'
|
|
29
51
|
};
|
|
30
52
|
```
|
|
31
53
|
|
|
32
|
-
In this case the context broker is
|
|
33
|
-
sending requests to port `4041` which is also the port used to receive NGSI requests. The IoT Agent is
|
|
34
|
-
|
|
54
|
+
In this case the context broker hostname is `orion` and is listening on port `1026`, the IoT Agent can be provisioned by
|
|
55
|
+
sending requests to port `4041` which is also the port used to receive NGSI requests. The IoT Agent is using the
|
|
56
|
+
`iotagent` database from a MongoDB instance at `localhost:27017` to store needed information (provisioned groups and
|
|
57
|
+
devices, etc.).
|
|
35
58
|
|
|
36
59
|
The remaining settings help to define the NGSI interactions - the IoT Agent will be using the `fiware-service=openiot`
|
|
37
60
|
and `fiware-service-path=/`. The default `type`for each created entity is `Thing`, although this can be overridden as
|
|
38
61
|
shown below. Devices will be registered for a period of one month and the IoT Agent will receive registration callbacks
|
|
39
62
|
at the URL `http://iot-agent:4041`.
|
|
40
63
|
|
|
41
|
-
All configuration settings can also updated using Docker environment variables.
|
|
64
|
+
All configuration settings can also updated using Docker environment variables. You can find more information about the
|
|
65
|
+
available configuration parameters and environment variables in the [Administration Guide](admin.md).
|
|
42
66
|
|
|
43
|
-
|
|
67
|
+
## Provisioning a Config Group
|
|
44
68
|
|
|
45
|
-
Settings which are common to a group of devices can be passed to the IoT Agent using the
|
|
46
|
-
|
|
47
|
-
|
|
69
|
+
Settings which are common to a group of devices can be passed to the IoT Agent using the Config Group API. Each config
|
|
70
|
+
group may override values previously defined in the global configuration if necessary. When using the config group API,
|
|
71
|
+
the `fiware-service` and `fiware-servicepath` headers will define the service and subservice to which the configuration
|
|
72
|
+
will be applied. Additionally, the `apikey` field is used to identify the configuration group. An example of a basic
|
|
73
|
+
config group is shown below:
|
|
48
74
|
|
|
49
75
|
```bash
|
|
50
76
|
curl -iX POST \
|
|
51
|
-
'http://localhost:4041/iot/
|
|
77
|
+
'http://localhost:4041/iot/groups' \
|
|
52
78
|
-H 'Content-Type: application/json' \
|
|
53
79
|
-H 'fiware-service: openiot' \
|
|
54
80
|
-H 'fiware-servicepath: /' \
|
|
55
81
|
-d '{
|
|
56
|
-
"
|
|
82
|
+
"groups": [
|
|
57
83
|
{
|
|
58
84
|
"apikey": "4jggokgpepnvsb2uv4s40d59ov",
|
|
59
|
-
"cbHost": "http://orion:1026",
|
|
60
85
|
"entity_type": "Device",
|
|
61
|
-
"resource": "/iot/
|
|
86
|
+
"resource": "/iot/json",
|
|
87
|
+
"attributes": [
|
|
88
|
+
{ "object_id": "t", "name": "temperature", "type": "Number" }
|
|
89
|
+
]
|
|
62
90
|
}
|
|
63
91
|
]
|
|
64
92
|
}'
|
|
@@ -66,12 +94,18 @@ curl -iX POST \
|
|
|
66
94
|
|
|
67
95
|
In this case an `apiKey` for identifying devices has been created and all interactions to the path `/iot/d` which
|
|
68
96
|
present this `apiKey` will be created as entities of `type=Device` rather than using the configuration default of
|
|
69
|
-
`type=Thing`.
|
|
70
|
-
|
|
97
|
+
`type=Thing`.
|
|
98
|
+
|
|
99
|
+
Additionally, the group has defined an attribute mapping for a measurement `t` to be mapped to `temperature` attribute
|
|
100
|
+
when receiving data from devices.
|
|
101
|
+
|
|
102
|
+
The config group would usual hold additional attribute mappings, commands and common static attributes as well.
|
|
71
103
|
|
|
72
|
-
|
|
104
|
+
## Provisioning an Individual Device
|
|
73
105
|
|
|
74
|
-
Settings which are specific to an individual device can be passed to the IoT Agent using the Device API
|
|
106
|
+
Settings which are specific to an individual device can be passed to the IoT Agent using the Device API. The
|
|
107
|
+
configuration provided in the Device API will override any settings defined in the Config Group API and the global
|
|
108
|
+
configuration as well. An example of a basic device configuration is shown below:
|
|
75
109
|
|
|
76
110
|
```bash
|
|
77
111
|
curl -iX POST \
|
|
@@ -86,7 +120,7 @@ curl -iX POST \
|
|
|
86
120
|
"entity_name": "urn:ngsi-ld:Motion:001",
|
|
87
121
|
"entity_type": "Motion",
|
|
88
122
|
"attributes": [
|
|
89
|
-
{ "object_id": "c", "name": "count", "type": "
|
|
123
|
+
{ "object_id": "c", "name": "count", "type": "Number" }
|
|
90
124
|
],
|
|
91
125
|
"static_attributes": [
|
|
92
126
|
{ "name":"refStore", "type": "Relationship", "value": "urn:ngsi-ld:Store:001"}
|
|
@@ -97,54 +131,81 @@ curl -iX POST \
|
|
|
97
131
|
'
|
|
98
132
|
```
|
|
99
133
|
|
|
100
|
-
|
|
101
|
-
of the
|
|
134
|
+
The device `motion001` has been provisioned to persist data to the Context Broker as an entity of `type=Motion` (instead
|
|
135
|
+
of the default `type=Thing`). The destination entity is identified by the `entity_name` field, which is set to
|
|
136
|
+
`urn:ngsi-ld:Motion:001`. The device has a single attribute mapping for a measurement `c` to be mapped to `count`
|
|
137
|
+
attribute, additionally to one defined in the group mapping (`temperature`). The device also has a static attribute
|
|
138
|
+
`refStore` which is a relationship to the entity `urn:ngsi-ld:Store:001`.
|
|
102
139
|
|
|
103
|
-
|
|
140
|
+
This information is combined with the common config group information whenever a measurement is received at the IoT
|
|
141
|
+
Agent and used to create or update the relevant entity in the Context Broker.
|
|
104
142
|
|
|
105
|
-
|
|
143
|
+
## Receiving measures from devices
|
|
144
|
+
|
|
145
|
+
In order to see the complete process from provisioning the groups and devices to receiving measures, we will show how a
|
|
146
|
+
device can send a measure to the IoT Agent. In this case, we will use the IoTA JSON as an example, using the HTTP
|
|
147
|
+
transport protocol. To reproduce the measure sending, you can use the following `curl` commands.
|
|
148
|
+
|
|
149
|
+
The device measures are sent to the South port of the IoT Agent which is listening in the port `7896`.
|
|
150
|
+
|
|
151
|
+
### Receiving a measure from a known Device
|
|
152
|
+
|
|
153
|
+
In this case, the device has been provisioned previously. We will use the `motion001` device defined in the previous
|
|
154
|
+
example. To simulate the device sending a measure, the following request is sent to the South port:
|
|
106
155
|
|
|
107
156
|
```bash
|
|
108
157
|
curl -iX POST \
|
|
109
|
-
'http://localhost:7896/iot/
|
|
110
|
-
-H 'Content-Type:
|
|
111
|
-
-d 'c
|
|
158
|
+
'http://localhost:7896/iot/json?k=4jggokgpepnvsb2uv4s40d59ov&i=motion001' \
|
|
159
|
+
-H 'Content-Type: application/json' \
|
|
160
|
+
-d '{"t":23,"c":1}'
|
|
112
161
|
```
|
|
113
162
|
|
|
114
|
-
The IoT Agent South port is listening to the path defined in the
|
|
163
|
+
The IoT Agent South port is listening to the path defined in the config group, and the API key is recognized to match.
|
|
115
164
|
Because the `device_id` is also recognized, the provisioned device configuration is used and its settings are combined
|
|
116
|
-
with the
|
|
117
|
-
|
|
165
|
+
with the config group.
|
|
166
|
+
|
|
167
|
+
Mapping has been found to use the `c` measurement as `count` and the `t` measurement as `temperature` attributes values.
|
|
168
|
+
The following context entity is created in the context broker:
|
|
118
169
|
|
|
119
170
|
```json
|
|
120
171
|
{
|
|
121
172
|
"id": "urn:ngsi-ld:Motion:001",
|
|
122
173
|
"type": "Motion",
|
|
123
|
-
"
|
|
174
|
+
"temperature": { "value": 23, "type": "Number" },
|
|
175
|
+
"count": { "value": 1, "type": "Number" },
|
|
124
176
|
"refStore": { "value": "urn:ngsi-ld:Store:001", "type": "Relationship" }
|
|
125
177
|
}
|
|
126
178
|
```
|
|
127
179
|
|
|
128
|
-
|
|
180
|
+
### Receiving a measure from an anonymous Device
|
|
181
|
+
|
|
182
|
+
When receiving a measure, it is not necessary to have the device provisioned. In this case, the IoT Agent will use the
|
|
183
|
+
config group configuration to create the device and the entity. This process is called "autoprovision" and it is enabled
|
|
184
|
+
by default in provisioned groups (for further information, review the
|
|
185
|
+
[Autoprovision](api.md#autoprovision-configuration-autoprovision) section in the API documentation).
|
|
129
186
|
|
|
130
|
-
|
|
131
|
-
to the South port:
|
|
187
|
+
Take as an example the following request from an anonymous device:
|
|
132
188
|
|
|
133
189
|
```bash
|
|
134
190
|
curl -iX POST \
|
|
135
|
-
'http://localhost:7896/iot/
|
|
136
|
-
-H 'Content-Type:
|
|
137
|
-
-d 't
|
|
191
|
+
'http://localhost:7896/iot/json?k=4jggokgpepnvsb2uv4s40d59ov&i=dev001' \
|
|
192
|
+
-H 'Content-Type: application/json' \
|
|
193
|
+
-d '{"t":13,"c":4}'
|
|
138
194
|
```
|
|
139
195
|
|
|
140
|
-
The IoT Agent South port is listen to the path defined in the
|
|
141
|
-
the
|
|
142
|
-
|
|
196
|
+
The IoT Agent South port is listen to the path defined in the config group, and the API key is recognized to match, so
|
|
197
|
+
the config group configuration will be used. No device has been provisioned with the `device_id=dev001`, so the IoT
|
|
198
|
+
Agent will only use the config group configuration.
|
|
199
|
+
|
|
200
|
+
A new entity will be created in the Context Broker with the `id` `Device:dev001` and the `type` `Device`. Only the `t`
|
|
201
|
+
measurement will be mapped to the `temperature` attribute, as defined in the config group. The remaining measurements
|
|
202
|
+
will be created as attributes with the same name. The following context entity will be created in the context broker:
|
|
143
203
|
|
|
144
204
|
```json
|
|
145
205
|
{
|
|
146
|
-
"id": "
|
|
206
|
+
"id": "Device:dev001",
|
|
147
207
|
"type": "Device",
|
|
148
|
-
"
|
|
208
|
+
"temperature": { "value": 13, "type": "Number" },
|
|
209
|
+
"c": { "value": 4, "type": "Number" }
|
|
149
210
|
}
|
|
150
211
|
```
|
package/doc/requirements.txt
CHANGED
package/doc/roadmap.md
CHANGED
|
@@ -25,10 +25,7 @@ Disclaimer:
|
|
|
25
25
|
The following list of features are planned to be addressed in the short term, and incorporated in a release of the
|
|
26
26
|
product:
|
|
27
27
|
|
|
28
|
-
- cgroup literal in configuration groups management API (
|
|
29
|
-
- Refactor Append Mode & initial entity ([#1413](https://github.com/telefonicaid/iotagent-node-lib/issues/1413))
|
|
30
|
-
- Native support for NGSI-v2 and LD ingestion ([#1451](https://github.com/telefonicaid/iotagent-node-lib/issues/1451))
|
|
31
|
-
- Remove plugins structure (bidirectional plugin) ([#1413](https://github.com/telefonicaid/iotagent-node-lib/issues/1413))
|
|
28
|
+
- cgroup literal in configuration groups management API ([#752](https://github.com/telefonicaid/iotagent-node-lib/issues/752))
|
|
32
29
|
- Add init and improve log traces ([#1452](https://github.com/telefonicaid/iotagent-node-lib/issues/1452))
|
|
33
30
|
- Remove InMemory registry for Devices and Groups ([#1429](https://github.com/telefonicaid/iotagent-node-lib/issues/1429))
|
|
34
31
|
|
|
@@ -37,7 +34,6 @@ product:
|
|
|
37
34
|
The following list of features are planned to be addressed in the medium term, typically within the subsequent
|
|
38
35
|
release(s) generated in the next 9 months after the next planned release:
|
|
39
36
|
|
|
40
|
-
- Allow to add metadata to attributes from measures ([#1453](https://github.com/telefonicaid/iotagent-node-lib/issues/1453))
|
|
41
37
|
- Cache support ([#1467](https://github.com/telefonicaid/iotagent-node-lib/issues/1467))
|
|
42
38
|
- MQTT per group advanced configuration (MQTT broker, topics) ([#1454](https://github.com/telefonicaid/iotagent-node-lib/issues/1454))
|
|
43
39
|
- Subscription based commands ([#1455](https://github.com/telefonicaid/iotagent-node-lib/issues/1455))
|
|
@@ -59,6 +55,10 @@ us if you wish to get involved in the implementation or influence the roadmap:
|
|
|
59
55
|
|
|
60
56
|
The following list contains all features that were in the roadmap and have already been implemented.
|
|
61
57
|
|
|
58
|
+
- Allow to add metadata to attributes from measures ([#1453](https://github.com/telefonicaid/iotagent-node-lib/issues/1453)) ([4.6.0](https://github.com/telefonicaid/iotagent-node-lib/releases/tag/4.0.0))
|
|
59
|
+
- Refactor Append Mode & initial entity ([#1413](https://github.com/telefonicaid/iotagent-node-lib/issues/1413)) ([4.0.0](https://github.com/telefonicaid/iotagent-node-lib/releases/tag/4.0.0))
|
|
60
|
+
- Native support for NGSI-v2 and LD ingestion ([#1451](https://github.com/telefonicaid/iotagent-node-lib/issues/1451)) ([4.0.0](https://github.com/telefonicaid/iotagent-node-lib/releases/tag/4.0.0))
|
|
61
|
+
- Remove plugins structure (bidirectional plugin) ([#1413](https://github.com/telefonicaid/iotagent-node-lib/issues/1413)) ([4.0.0](https://github.com/telefonicaid/iotagent-node-lib/releases/tag/4.0.0))
|
|
62
62
|
- Refactor entities-NGSI-v2.js module ([#1166](https://github.com/telefonicaid/iotagent-node-lib/issues/1166)) ([3.0.0](https://github.com/telefonicaid/iotagent-node-lib/releases/tag/3.0.0))
|
|
63
63
|
- Accept JEXL Expressions for entity name in autoprovisioned devices (entityNameExp) ([#1145](https://github.com/telefonicaid/iotagent-node-lib/issues/1145)) ([2.22.0](https://github.com/telefonicaid/iotagent-node-lib/releases/tag/2.22.0))
|
|
64
64
|
- Improve command functionalities (binary data + expression + mapping) ([2.22.0](https://github.com/telefonicaid/iotagent-node-lib/releases/tag/2.22.0))
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
ARG IMAGE_TAG=12.
|
|
1
|
+
ARG IMAGE_TAG=12.6-slim
|
|
2
2
|
FROM debian:${IMAGE_TAG}
|
|
3
3
|
|
|
4
4
|
ARG CLEAN_DEV_TOOLS
|
|
@@ -16,7 +16,7 @@ RUN \
|
|
|
16
16
|
# Install dependencies
|
|
17
17
|
apt-get -y install \
|
|
18
18
|
wget \
|
|
19
|
-
mosquitto && \
|
|
19
|
+
mosquitto mosquitto-clients && \
|
|
20
20
|
cp /etc/mosquitto/mosquitto.conf /etc/mosquitto/mosquitto.conf.orig && \
|
|
21
21
|
chmod 755 /bin/startMosquitto.sh && \
|
|
22
22
|
mkdir -p /var/log/mosquitto && \
|
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
Thi directory containts the Dockerfile (and associated files) for a container of
|
|
2
|
-
This container is provide as a help for users to test with MQTT, but it
|
|
1
|
+
Thi directory containts the Dockerfile (and associated files) for a container of
|
|
2
|
+
[mosquitto MQTT broker](https://mosquitto.org). This container is provide as a help for users to test with MQTT, but it
|
|
3
|
+
is just an auxiliary material in this repository.
|
|
3
4
|
|
|
4
5
|
The following releases matches with eclipse-mosquitto version:
|
|
5
|
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
6
|
+
|
|
7
|
+
- 2.2.0 uses mosquitto-2.0.11 from Debian 12
|
|
8
|
+
- 2.1.0 uses mosquitto-2.0.11 from Debian 12
|
|
9
|
+
- 2.0.0 uses mosquitto-2.0.11 from Debian 11
|
|
10
|
+
- 1.6.0 uses mosquitto-1.6.10-1.el7.x86_64 (from Centos7)
|
|
11
|
+
- 1.5.0 uses mosquitto-1.6.10-1.el7.x86_64 (from Centos7)
|
|
12
|
+
- 1.4.0 uses mosquitto-1.6.10-1.el7.x86_64 (from Centos7)
|
|
13
|
+
- 1.3.0 uses mosquitto-1.6.8-1.el7.x86_64 (from Centos7)
|
|
14
|
+
- 1.2.0 uses mosquitto-1.6.7-1.el7.x86_64 (from Centos7)
|
|
15
|
+
- 1.1.0 uses mosquitto-1.5.8-1.el7.x86_64 (from Centos7)
|
|
16
|
+
- 1.0.0 uses mosquitto-1.4.8-1.el7.x86_64 (from Centos7)
|
package/lib/commonConfig.js
CHANGED
|
@@ -156,7 +156,8 @@ function processEnvironmentVariables() {
|
|
|
156
156
|
'IOTA_FALLBACK_TENANT',
|
|
157
157
|
'IOTA_FALLBACK_PATH',
|
|
158
158
|
'IOTA_LD_SUPPORT_NULL',
|
|
159
|
-
'IOTA_LD_SUPPORT_DATASET_ID'
|
|
159
|
+
'IOTA_LD_SUPPORT_DATASET_ID',
|
|
160
|
+
'IOTA_EXPRESS_LIMIT'
|
|
160
161
|
];
|
|
161
162
|
const iotamVariables = [
|
|
162
163
|
'IOTA_IOTAM_URL',
|
|
@@ -468,6 +469,11 @@ function processEnvironmentVariables() {
|
|
|
468
469
|
? config.defaultEntityNameConjunction
|
|
469
470
|
: ':';
|
|
470
471
|
}
|
|
472
|
+
if (process.env.IOTA_EXPRESS_LIMIT) {
|
|
473
|
+
config.expressLimit = process.env.IOTA_EXPRESS_LIMIT;
|
|
474
|
+
} else {
|
|
475
|
+
config.expressLimit = config.expressLimit ? config.expressLimit : '1mb';
|
|
476
|
+
}
|
|
471
477
|
}
|
|
472
478
|
|
|
473
479
|
function setConfig(newConfig) {
|
package/lib/constants.js
CHANGED
|
@@ -45,22 +45,19 @@ const context = {
|
|
|
45
45
|
op: 'IoTAgentNGSI.Global'
|
|
46
46
|
};
|
|
47
47
|
|
|
48
|
+
/* eslint-disable-next-line no-unused-vars */
|
|
48
49
|
function activateStatLogs(newConfig, callback) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
);
|
|
61
|
-
} else {
|
|
62
|
-
callback();
|
|
63
|
-
}
|
|
50
|
+
async.series([
|
|
51
|
+
apply(statsRegistry.globalLoad, {
|
|
52
|
+
deviceCreationRequests: 0,
|
|
53
|
+
deviceRemovalRequests: 0,
|
|
54
|
+
measureRequests: 0,
|
|
55
|
+
raiseAlarm: 0,
|
|
56
|
+
releaseAlarm: 0,
|
|
57
|
+
updateEntityRequestsOk: 0,
|
|
58
|
+
updateEntityRequestsError: 0
|
|
59
|
+
})
|
|
60
|
+
], callback);
|
|
64
61
|
}
|
|
65
62
|
|
|
66
63
|
/**
|
package/lib/jexlTranformsMap.js
CHANGED
|
@@ -80,7 +80,9 @@ const map = {
|
|
|
80
80
|
localestring: (d, timezone, options) => new Date(d).toLocaleString(timezone, options),
|
|
81
81
|
now: () => Date.now(),
|
|
82
82
|
hextostring: (val) =>
|
|
83
|
-
new TextDecoder().decode(new Uint8Array(val.match(/.{1,2}/g).map((byte) => parseInt(byte, 16))))
|
|
83
|
+
new TextDecoder().decode(new Uint8Array(val.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)))),
|
|
84
|
+
valuePicker: (val,pick) => Object.entries(val).filter(([, v]) => v === pick).map(([k,]) => k),
|
|
85
|
+
valuePickerMulti: (val,pick) => Object.entries(val).filter(([, v]) => pick.includes(v)).map(([k,]) => k)
|
|
84
86
|
};
|
|
85
87
|
|
|
86
88
|
exports.map = map;
|
package/lib/model/dbConn.js
CHANGED
|
@@ -190,10 +190,7 @@ function configureDb(callback) {
|
|
|
190
190
|
/*jshint camelcase:false, validthis:true */
|
|
191
191
|
const currentConfig = config.getConfig();
|
|
192
192
|
|
|
193
|
-
if (
|
|
194
|
-
(currentConfig.deviceRegistry && currentConfig.deviceRegistry.type === 'mongodb') ||
|
|
195
|
-
(currentConfig.stats && currentConfig.stats.persistence === true)
|
|
196
|
-
) {
|
|
193
|
+
if (currentConfig.deviceRegistry && currentConfig.deviceRegistry.type === 'mongodb') {
|
|
197
194
|
if (!currentConfig.mongodb || !currentConfig.mongodb.host) {
|
|
198
195
|
logger.fatal(context, 'MONGODB-003: No host found for MongoDB driver.');
|
|
199
196
|
callback(new errors.BadConfiguration('No host found for MongoDB driver'));
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
24
|
let alarmRepository = {};
|
|
25
|
+
const statsRegistry = require('../stats/statsRegistry');
|
|
25
26
|
const logger = require('logops');
|
|
26
27
|
const context = {
|
|
27
28
|
op: 'IoTAgentNGSI.Alarms'
|
|
@@ -41,6 +42,7 @@ function raise(alarmName, description) {
|
|
|
41
42
|
};
|
|
42
43
|
|
|
43
44
|
logger.error(context, 'Raising [%s]: %j', alarmName, description);
|
|
45
|
+
statsRegistry.add('raiseAlarm', 1, function () {});
|
|
44
46
|
}
|
|
45
47
|
}
|
|
46
48
|
|
|
@@ -53,6 +55,7 @@ function release(alarmName) {
|
|
|
53
55
|
if (alarmRepository[alarmName]) {
|
|
54
56
|
delete alarmRepository[alarmName];
|
|
55
57
|
logger.error(context, 'Releasing [%s]', alarmName);
|
|
58
|
+
statsRegistry.add('releaseAlarm', 1, function () {});
|
|
56
59
|
}
|
|
57
60
|
}
|
|
58
61
|
|
|
@@ -176,7 +176,7 @@ function getByName(name, service, subservice, callback) {
|
|
|
176
176
|
getByNameAndType(name, null, service, subservice, callback);
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
-
function update(device, callback) {
|
|
179
|
+
function update(previousDevice, device, callback) {
|
|
180
180
|
registeredDevices[device.service][device.id] = deepClone(device);
|
|
181
181
|
callback(null, device);
|
|
182
182
|
}
|
|
@@ -290,9 +290,9 @@ function getByName(name, service, servicepath, callback) {
|
|
|
290
290
|
*
|
|
291
291
|
* @param {Object} device Device object with the new values to write.
|
|
292
292
|
*/
|
|
293
|
-
function update(device, callback) {
|
|
293
|
+
function update(previousDevice, device, callback) {
|
|
294
294
|
logger.debug(context, 'Storing updated values for device [%s]:\n%s', device.id, JSON.stringify(device, null, 4));
|
|
295
|
-
getDevice(device.id,
|
|
295
|
+
getDevice(device.id, previousDevice.apikey, device.service, device.subservice, function (error, data) {
|
|
296
296
|
if (error) {
|
|
297
297
|
callback(error);
|
|
298
298
|
} else {
|
|
@@ -444,8 +444,8 @@ function unregisterDevice(id, apikey, service, subservice, callback) {
|
|
|
444
444
|
});
|
|
445
445
|
}
|
|
446
446
|
|
|
447
|
-
function updateRegisterDevice(deviceObj, entityInfoUpdated, callback) {
|
|
448
|
-
deviceHandler.updateRegisterDevice(deviceObj, entityInfoUpdated, callback);
|
|
447
|
+
function updateRegisterDevice(deviceObj, previousDevice, entityInfoUpdated, callback) {
|
|
448
|
+
deviceHandler.updateRegisterDevice(deviceObj, previousDevice, entityInfoUpdated, callback);
|
|
449
449
|
}
|
|
450
450
|
|
|
451
451
|
/**
|
|
@@ -518,7 +518,8 @@ function getDevice(deviceId, apikey, service, subservice, callback) {
|
|
|
518
518
|
* @param {String} device JSON object contain the device to update.
|
|
519
519
|
*/
|
|
520
520
|
function updateDevice(device, callback) {
|
|
521
|
-
|
|
521
|
+
logger.debug(context, 'updateDevice %j', device);
|
|
522
|
+
config.getRegistry().update(device, device, callback);
|
|
522
523
|
}
|
|
523
524
|
|
|
524
525
|
/**
|
|
@@ -182,7 +182,7 @@ function updateEntityNgsiLD(deviceData, updatedDevice, callback) {
|
|
|
182
182
|
*
|
|
183
183
|
* @param {Object} deviceObj Object with all the device information (mandatory).
|
|
184
184
|
*/
|
|
185
|
-
function updateRegisterDeviceNgsiLD(deviceObj, entityInfoUpdated, callback) {
|
|
185
|
+
function updateRegisterDeviceNgsiLD(deviceObj, previousDevice, entityInfoUpdated, callback) {
|
|
186
186
|
if (!deviceObj.id || !deviceObj.type) {
|
|
187
187
|
callback(new errors.MissingAttributes('Id or device missing', deviceObj));
|
|
188
188
|
return;
|
|
@@ -280,7 +280,7 @@ function updateRegisterDeviceNgsiLD(deviceObj, entityInfoUpdated, callback) {
|
|
|
280
280
|
apply(
|
|
281
281
|
config.getRegistry().get,
|
|
282
282
|
deviceObj.id,
|
|
283
|
-
|
|
283
|
+
previousDevice.apikey,
|
|
284
284
|
deviceObj.service,
|
|
285
285
|
deviceObj.subservice
|
|
286
286
|
),
|
|
@@ -289,7 +289,7 @@ function updateRegisterDeviceNgsiLD(deviceObj, entityInfoUpdated, callback) {
|
|
|
289
289
|
apply(combineWithNewDevice, deviceObj),
|
|
290
290
|
apply(registrationUtils.sendRegistrations, false),
|
|
291
291
|
apply(registrationUtils.processContextRegistration, deviceObj),
|
|
292
|
-
config.getRegistry().update
|
|
292
|
+
apply(config.getRegistry().update, previousDevice)
|
|
293
293
|
],
|
|
294
294
|
callback
|
|
295
295
|
);
|
|
@@ -299,7 +299,7 @@ function updateRegisterDeviceNgsiLD(deviceObj, entityInfoUpdated, callback) {
|
|
|
299
299
|
apply(
|
|
300
300
|
config.getRegistry().get,
|
|
301
301
|
deviceObj.id,
|
|
302
|
-
|
|
302
|
+
previousDevice.apikey,
|
|
303
303
|
deviceObj.service,
|
|
304
304
|
deviceObj.subservice
|
|
305
305
|
),
|
|
@@ -308,7 +308,7 @@ function updateRegisterDeviceNgsiLD(deviceObj, entityInfoUpdated, callback) {
|
|
|
308
308
|
apply(combineWithNewDevice, deviceObj),
|
|
309
309
|
apply(registrationUtils.sendRegistrations, false),
|
|
310
310
|
apply(registrationUtils.processContextRegistration, deviceObj),
|
|
311
|
-
config.getRegistry().update
|
|
311
|
+
apply(config.getRegistry().update, previousDevice)
|
|
312
312
|
],
|
|
313
313
|
callback
|
|
314
314
|
);
|
|
@@ -38,11 +38,11 @@ const deviceHandlerV2 = require('./devices-NGSI-v2');
|
|
|
38
38
|
*
|
|
39
39
|
* @param {Object} deviceObj Object with all the device information (mandatory).
|
|
40
40
|
*/
|
|
41
|
-
function updateRegisterDeviceNgsiMixed(deviceObj, entityInfoUpdated, callback) {
|
|
41
|
+
function updateRegisterDeviceNgsiMixed(deviceObj, previousDevice, entityInfoUpdated, callback) {
|
|
42
42
|
if (config.checkNgsiLD(deviceObj)) {
|
|
43
|
-
deviceHandlerLD.updateRegisterDevice(deviceObj, entityInfoUpdated, callback);
|
|
43
|
+
deviceHandlerLD.updateRegisterDevice(deviceObj, previousDevice, entityInfoUpdated, callback);
|
|
44
44
|
} else {
|
|
45
|
-
deviceHandlerV2.updateRegisterDevice(deviceObj, entityInfoUpdated, callback);
|
|
45
|
+
deviceHandlerV2.updateRegisterDevice(deviceObj, previousDevice, entityInfoUpdated, callback);
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
|
|
@@ -247,7 +247,7 @@ function updateEntityNgsi2(deviceData, updatedDevice, callback) {
|
|
|
247
247
|
*
|
|
248
248
|
* @param {Object} deviceObj Object with all the device information (mandatory).
|
|
249
249
|
*/
|
|
250
|
-
function updateRegisterDeviceNgsi2(deviceObj, entityInfoUpdated, callback) {
|
|
250
|
+
function updateRegisterDeviceNgsi2(deviceObj, previousDevice, entityInfoUpdated, callback) {
|
|
251
251
|
if (!deviceObj.id || !deviceObj.type) {
|
|
252
252
|
callback(new errors.MissingAttributes('Id or device missing', deviceObj));
|
|
253
253
|
return;
|
|
@@ -352,7 +352,7 @@ function updateRegisterDeviceNgsi2(deviceObj, entityInfoUpdated, callback) {
|
|
|
352
352
|
apply(
|
|
353
353
|
config.getRegistry().get,
|
|
354
354
|
deviceObj.id,
|
|
355
|
-
|
|
355
|
+
previousDevice.apikey, // it could be updated
|
|
356
356
|
deviceObj.service,
|
|
357
357
|
deviceObj.subservice
|
|
358
358
|
),
|
|
@@ -361,7 +361,7 @@ function updateRegisterDeviceNgsi2(deviceObj, entityInfoUpdated, callback) {
|
|
|
361
361
|
apply(combineWithNewDevice, deviceObj),
|
|
362
362
|
apply(registrationUtils.sendRegistrations, false),
|
|
363
363
|
apply(registrationUtils.processContextRegistration, deviceObj),
|
|
364
|
-
config.getRegistry().update
|
|
364
|
+
apply(config.getRegistry().update, previousDevice)
|
|
365
365
|
],
|
|
366
366
|
callback
|
|
367
367
|
);
|
|
@@ -371,7 +371,7 @@ function updateRegisterDeviceNgsi2(deviceObj, entityInfoUpdated, callback) {
|
|
|
371
371
|
apply(
|
|
372
372
|
config.getRegistry().get,
|
|
373
373
|
deviceObj.id,
|
|
374
|
-
|
|
374
|
+
previousDevice.apikey,
|
|
375
375
|
deviceObj.service,
|
|
376
376
|
deviceObj.subservice
|
|
377
377
|
),
|
|
@@ -380,7 +380,7 @@ function updateRegisterDeviceNgsi2(deviceObj, entityInfoUpdated, callback) {
|
|
|
380
380
|
apply(combineWithNewDevice, deviceObj),
|
|
381
381
|
apply(registrationUtils.sendRegistrations, false),
|
|
382
382
|
apply(registrationUtils.processContextRegistration, deviceObj),
|
|
383
|
-
config.getRegistry().update
|
|
383
|
+
apply(config.getRegistry().update, previousDevice)
|
|
384
384
|
],
|
|
385
385
|
callback
|
|
386
386
|
);
|
|
@@ -123,7 +123,7 @@ function listGroups(service, limit, offset, callback) {
|
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
function checkServiceIdentity(service, subservice, deviceGroup, callback) {
|
|
126
|
-
if (deviceGroup.service === service && deviceGroup.subservice === subservice) {
|
|
126
|
+
if (deviceGroup.service === service.toLowerCase() && deviceGroup.subservice === subservice) {
|
|
127
127
|
callback(null, deviceGroup);
|
|
128
128
|
} else {
|
|
129
129
|
callback(new errors.MismatchedService(service, subservice));
|