/
FIWARE IoT over IOTA.postman_collection.json
265 lines (265 loc) · 42.2 KB
/
FIWARE IoT over IOTA.postman_collection.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
{
"info": {
"_postman_id": "68eeeb6f-30c7-4300-ae6d-a41813e13155",
"name": "FIWARE IoT over IOTA Tangle",
"description": "This tutorial extends the connection of IoT devices connecting to FIWARE to use an alternate transport. The \n[UltraLight 2.0](https://fiware-iotagent-ul.readthedocs.io/en/latest/usermanual/index.html#user-programmers-manual) IoT \nAgent created in the [previous tutorial](https://github.com/FIWARE/tutorials.IoT-Agent) is reconfigured to communicate \nwith a set of dummy IoT devices which transfer secure messages over the \n[IOTA Tangle](https://iota-beginners-guide.com/dlt/tangle/). An additional gateway component is added to the \narchitecture of the previous [MQTT tutorial](https://github.com/FIWARE/tutorials.IoT-over-MQTT) to allow for secure \nindelible transactions across a distributed ledger network.\n\nThe tutorial is mainly concerned with the architecture of the custom components, but uses [cUrl](https://ec.haxx.se/) \ncommands where necessary, and is also available as \n[Postman documentation](https://fiware.github.io/tutorials.IoT-Agent/)\n\n# What is IOTA?\n\n> “Hansel took his little sister by the hand, and followed the pebbles which shone like newly-coined silver pieces, and \n> showed them the way.”\n> \n> ― Jacob Grimm, Grimm's Fairy Tales\n\nThe [IOTA Tangle](https://www.iota.org/get-started/what-is-iota) is a directed acyclic graph which can be used as a \ndistributed ledger. It is not a traditional blockchain, but works with the concept of a Tangle which contains the \ncurrent transaction history and links from parents to child transations which provide a single source of truth in a \ndistributed network. Whenever information is persisted to the tangle it is replicated across all nodes so that any \nclient, anywhere around the world can send valid transactions to a Node.\n\nIOTA positions itself as being an ideal distributed ledger for IoT due to its feeless nature and scalable distributed \nstructure. Obviously when architecting any smart system, the developer needs to compromise between various factors such \nas price, speed, reliability, security and so on. The previous MQTT tutorial was fast, but contained no security elements \nand was vulnerable to malicious attack. An IOTA-based IoT system will automatically include secure logging of all events \nand therefore could be used to for charging customers on an event-by-event basis.\n\nA hybrid system could also be envisaged where some frequent but low risk transactions could be made using a standard \nMQTT transport (e.g. continuous tracking of the location an ARV), whereas infrequent but chargeable events could be made \nusing a secure system like IOTA (e.g. credit card payment for an entire trip)\n\nThe basic IOTA architecture includes the following basic components:\n\n* **Clients**: Users of an IOTA network (wallets, apps, etc.) that send transactions to nodes to attach to the Tangle.\n* **Nodes**: Connected devices responsible for ensuring the integrity of the Tangle. These devices form an IOTA \n network.\n* **Tangle**: An attached data structure (public ledger, main ledger), which is replicated on all nodes in an IOTA \n network.\n \n\nFor the purpose of this tutorial, all data from the dummy devices is being stored within the IOTA Tangle. Each device \nreading will be placed in a transaction object and attached to the IOTA Tangle, once attached it cannot be changed and \nis immutable. It obviously takes time for all nodes to agree that a transaction has occurred, and therefore all \ncommunication should be considered as asynchronous.\n\nThe IOT Agent for Ultralight currently offers three standard transport mechanisms - HTTP, MQTT and AMPQ. Whereas it \nwould be possible to create a new binding directly for IOTA, in this case, it makes more sense to re-use the existing \nasynchronous MQTT binding and extend using a gateway solution where a separate micro-service deals with the IOTA \nmessages. IoT Agents based on gateway solutions already exist for [OPC-UA](https://iotagent-opcua.readthedocs.io/) and \n[LoRaWAN](https://fiware-lorawan.readthedocs.io/). In the case of the IoT Agent for OPC-UA for example, in its \n[own Tutorial](https://iotagent-opcua.readthedocs.io/en/latest/opc_ua_agent_tutorial/index.html#step-by-step-tutorial), \ndevice readings are passed to an OPC-UA server and the IoT Agent in turn subscribes to the OPC-UA server and transforms \nmessages into NGSI format. With the Gateway solution described in this tutorial effectively MQTT is now just being used \nas a message bus, so we can provision our IoT devices as MQTT devices and intercept the relevant MQTT topics to \ntransform the data into IOTA Tangle transactions to talk to IOTA Tangle enabled devices. The payload of each message \ncontinues to use the existing \n[UltraLight 2.0](https://fiware-iotagent-ul.readthedocs.io/en/latest/usermanual/index.html#user-programmers-manual) \nsyntax and therefore we can continue to used the same FIWARE generic enabler to connect the devices. It is merely the \nunderlying **transport** which has been customized in this scenario.\n\n#### Mosquitto MQTT Broker\n\n[Mosquitto](https://mosquitto.org/) is a readily available, open source MQTT broker which will be used during this \ntutorial. It is available licensed under EPL/EDL. More information can be found at `https://mosquitto.org/`\n\n#### Device Monitor\n\nFor the purpose of this tutorial, a series of dummy IoT devices have been created, which will be attached to the context \nbroker. Details of the architecture and protocol used can be found in the \n[IoT Sensors tutorial](https://github.com/FIWARE/tutorials.IoT-Sensors/tree/NGSI-v2) The state of each device can be \nseen on the UltraLight device monitor web page found at: `http://localhost:3000/device/monitor`\n\n![](https://fiware.github.io//tutorials.IoT-over-IOTA/img/device-monitor.png)\n\n# Architecture\n\nThis application builds on the components created in \n[previous tutorials](https://github.com/FIWARE/tutorials.IoT-Agent/). It will make use of two FIWARE components - the \n[Orion Context Broker](https://fiware-orion.readthedocs.io/en/latest/) and the \n[IoT Agent for UltraLight 2.0](https://fiware-iotagent-ul.readthedocs.io/en/latest/). Usage of the Orion Context Broker \nis sufficient for an application to qualify as *“Powered by FIWARE”*. Both the Orion Context Broker and the IoT Agent \nrely on open source [MongoDB](https://www.mongodb.com/) technology to keep persistence of the information they hold. We \nwill also be using the dummy IoT devices created in the \n[previous tutorial](https://github.com/FIWARE/tutorials.IoT-Agent/) Additionally we will add an instance of the \n[Mosquitto](https://mosquitto.org/) MQTT broker which is open source and available under the EPL/EDL and create a custom \n**MQTT-IOTA Gateway** to enable us to persist commands to the IOTA Tangle and to subscribe to topics to receive \nmeasurements and command acknowledgements when they occur.\n\nTherefore the overall architecture will consist of the following elements:\n\n* The FIWARE [Orion Context Broker](https://fiware-orion.readthedocs.io/en/latest/) which will receive requests using \n [NGSI-v2](https://fiware.github.io/specifications/OpenAPI/ngsiv2)\n* The FIWARE [IoT Agent for UltraLight 2.0](https://fiware-iotagent-ul.readthedocs.io/en/latest/) which will:\n * receive southbound requests using [NGSI-v2](https://fiware.github.io/specifications/OpenAPI/ngsiv2) and convert \n them to \n [UltraLight 2.0](https://fiware-iotagent-ul.readthedocs.io/en/latest/usermanual/index.html#user-programmers-manual) \n MQTT topics for the MQTT Broker\n * listen to the **MQTT Broker** on registered topics to send measurements northbound\n* The [Mosquitto](https://mosquitto.org/) **MQTT Broker** which acts as a central communication point, passing MQTT \n topics between the **IoT Agent** and IoT devices as necessary.\n* The underlying [MongoDB](https://www.mongodb.com/) database :\n * Used by the **Orion Context Broker** to hold context data information such as data entities, subscriptions and \n registrations\n * Used by the **IoT Agent** to hold device information such as device URLs and Keys\n* A webserver acting as set of [dummy IoT devices](https://github.com/FIWARE/tutorials.IoT-Sensors/tree/NGSI-v2) using \n the \n [UltraLight 2.0](https://fiware-iotagent-ul.readthedocs.io/en/latest/usermanual/index.html#user-programmers-manual) \n protocol running over the IOTA Tangle.\n* An MQTT-IOTA gateway which persists MQTT topic messages to the tangle and vice-vera.\n \n\nSince all interactions between the elements are initiated by HTTP or MQTT requests over TCP, the entities can be \ncontainerized and run from exposed ports.\n\n![](https://fiware.github.io//tutorials.IoT-over-IOTA/img/architecture.png)\n\nThe necessary configuration information for wiring up the Mosquitto MQTT Broker, the IoT devices and the IoT Agent can \nbe seen in the services section of the associated `docker-compose.yml` file:\n\n## Mosquitto Configuration\n\n``` yaml\nmosquitto:\n image: eclipse-mosquitto\n hostname: mosquitto\n container_name: mosquitto\n networks:\n - default\n expose:\n - \"1883\"\n - \"9001\"\n ports:\n - \"1883:1883\"\n - \"9001:9001\"\n volumes:\n - ./mosquitto/mosquitto.conf:/mosquitto/config/mosquitto.conf\n\n```\n\nThe `mosquitto` container is listening on two ports:\n\n* Port `1883` is exposed so we can post MQTT topics\n* Port `9001` is the standard port for HTTP/Websocket communications\n \n\nThe attached volume is a \n[configuration file](https://github.com/FIWARE/tutorials.IoT-over-MQTT/blob/master/mosquitto/mosquitto.conf) used to \nincrease the debug level of the MQTT Message Broker.\n\n## Dummy IoT Devices Configuration\n\n``` yaml\ntutorial:\n image: quay.io/fiware/tutorials.context-provider\n hostname: iot-sensors\n container_name: fiware-tutorial\n networks:\n - default\n expose:\n - \"3000\"\n - \"3001\"\n ports:\n - \"3000:3000\"\n - \"3001:3001\"\n environment:\n - \"DEBUG=tutorial:*\"\n - \"WEB_APP_PORT=3000\"\n - \"DUMMY_DEVICES_PORT=3001\"\n - \"DUMMY_DEVICES_API_KEYS=1068318794,3020035,3314136,3089326\"\n - \"DUMMY_DEVICES_TRANSPORT=IOTA\"\n - \"IOTA_NODE=https://chrysalis-nodes.iota.cafe\"\n - \"IOTA_MESSAGE_INDEX=fiware\"\n\n```\n\nThe `tutorial` container is listening on two ports:\n\n* Port `3000` is exposed so we can see the web page displaying the Dummy IoT devices.\n* Port `3001` is exposed purely for tutorial access - so that cUrl or Postman can make UltraLight commands without \n being part of the same network.\n \n\nThe `tutorial` container is driven by environment variables as shown:\n\n| Key | Value | Description |\n| --- | --- | --- |\n| DEBUG | `tutorial:*` | Debug flag used for logging |\n| WEB_APP_PORT | `3000` | Port used by web-app which displays the dummy device data |\n| DUMMY_DEVICES_PORT | `3001` | Port used by the dummy IoT devices to receive commands |\n| DUMMY_DEVICES_API_KEYS | `4jggokgpepnvsb2uv4s40d59ov` | List of security key used for UltraLight interactions - used to ensure the integrity of interactions between the devices and the IoT Agent |\n| DUMMY_DEVICES_TRANSPORT | `IOTA` | The transport protocol used by the dummy IoT devices |\n| IOTA_NODE | `https://chrysalis-nodes.iota.cafe` | Starting IOTA node for the Gateway to connect to |\n| IOTA_MESSAGE_INDEX | `fiware` | Message index used to persist the data devices |\n\nThe other `tutorial` container configuration values described in the YAML file are not used in this tutorial.\n\n## IoT Agent for UltraLight 2.0 Configuration\n\nThe [IoT Agent for UltraLight 2.0](https://fiware-iotagent-ul.readthedocs.io/en/latest/) can be instantiated within a \nDocker container. An official Docker image is available from [Docker Hub](https://hub.docker.com/r/fiware/iotagent-ul/) \ntagged `fiware/iotagent-ul`. The necessary configuration can be seen below:\n\n``` yaml\niot-agent:\n image: quay.io/fiware/iotagent-ul:latest\n hostname: iot-agent\n container_name: fiware-iot-agent\n depends_on:\n - mongo-db\n networks:\n - default\n expose:\n - \"4041\"\n ports:\n - \"4041:4041\"\n environment:\n - IOTA_CB_HOST=orion\n - IOTA_CB_PORT=1026\n - IOTA_NORTH_PORT=4041\n - IOTA_REGISTRY_TYPE=mongodb\n - IOTA_LOG_LEVEL=DEBUG\n - IOTA_TIMESTAMP=true\n - IOTA_CB_NGSI_VERSION=v2\n - IOTA_AUTOCAST=true\n - IOTA_MONGO_HOST=mongo-db\n - IOTA_MONGO_PORT=27017\n - IOTA_MONGO_DB=iotagentul\n - IOTA_PROVIDER_URL=http://iot-agent:4041\n - IOTA_MQTT_HOST=mosquitto\n - IOTA_MQTT_PORT=1883\n\n```\n\nThe `iot-agent` container relies on the presence of the Orion Context Broker and uses a MongoDB database to hold device \ninformation such as device URLs and Keys. The container is listening on a single port:\n\n* Port `4041` is exposed purely for tutorial access - so that cUrl or Postman can make provisioning commands without \n being part of the same network.\n \n\nThe `iot-agent` container is driven by environment variables as shown:\n\n| Key | Value | Description |\n| --- | --- | --- |\n| IOTA_CB_HOST | `orion` | Hostname of the context broker to update context |\n| IOTA_CB_PORT | `1026` | Port that context broker listens on to update context |\n| IOTA_NORTH_PORT | `4041` | Port used for Configuring the IoT Agent and receiving context updates from the context broker |\n| IOTA_REGISTRY_TYPE | `mongodb` | Whether to hold IoT device info in memory or in a database |\n| IOTA_LOG_LEVEL | `DEBUG` | The log level of the IoT Agent |\n| IOTA_TIMESTAMP | `true` | Whether to supply timestamp information with each measurement received from attached devices |\n| IOTA_CB_NGSI_VERSION | `v2` | Whether to supply use NGSI v2 when sending updates for active attributes |\n| IOTA_AUTOCAST | `true` | Ensure Ultralight number values are read as numbers not strings |\n| IOTA_MONGO_HOST | `context-db` | The hostname of mongoDB - used for holding device information |\n| IOTA_MONGO_PORT | `27017` | The port mongoDB is listening on |\n| IOTA_MONGO_DB | `iotagentul` | The name of the database used in mongoDB |\n| IOTA_PROVIDER_URL | `http://iot-agent:4041` | URL passed to the Context Broker when commands are registered, used as a forwarding URL location when the Context Broker issues a command to a device |\n| IOTA_MQTT_HOST | `mosquitto` | The hostname of the MQTT Broker |\n| IOTA_MQTT_PORT | `1883` | The port the MQTT Broker is listening on to receive topics |\n\nAs you can see, use of the MQTT transport is driven by only two environment variables `IOTA_MQTT_HOST` and \n`IOTA_MQTT_PORT`\n\n## MQTT-IOTA Gateway Configuration\n\n``` yaml\niota-gateway:\n image: iota-gateway\n hostname: iota-gateway\n container_name: iota-gateway\n build:\n context: iota-gateway\n dockerfile: Dockerfile\n networks:\n - default\n environment:\n - \"DEBUG=gateway:*\"\n - \"MQTT_BROKER_URL=mqtt://mosquitto\"\n - \"IOTA_NODE=https://chrysalis-nodes.iota.cafe\"\n - \"IOTA_MESSAGE_INDEX=fiware\"\n\n```\n\nThe `iota-gateway` container is a middleware connecting to the MQTT broker and reading and persisting transactions onto \nIOTA Tangle. This middleware therefore needs to connect to both the MQTT broker and the IOTA Tangle and repeats some of \nthe parameters described above.\n\n# Prerequisites\n\n## Docker and Docker Compose\n\nTo keep things simple all components will be run using [Docker](https://www.docker.com). **Docker** is a container \ntechnology which allows to different components isolated into their respective environments.\n\n* To install Docker on Windows follow the instructions [here](https://docs.docker.com/docker-for-windows/)\n* To install Docker on Mac follow the instructions [here](https://docs.docker.com/docker-for-mac/)\n* To install Docker on Linux follow the instructions [here](https://docs.docker.com/install/)\n \n\n**Docker Compose** is a tool for defining and running multi-container Docker applications. A \n[YAML file](https://raw.githubusercontent.com/Fiware/tutorials.IoT-over-MQTT/master/docker-compose.yml) is used \nconfigure the required services for the application. This means all container services can be brought up in a single \ncommand. Docker Compose is installed by default as part of Docker for Windows and Docker for Mac, however Linux users \nwill need to follow the instructions found [here](https://docs.docker.com/compose/install/)\n\nYou can check your current **Docker** and **Docker Compose** versions using the following commands:\n\n``` console\ndocker-compose -v\ndocker version\n\n```\n\nPlease ensure that you are using Docker version 20.10 or higher and Docker Compose 1.29 or higher and upgrade if \nnecessary.\n\n## Cygwin for Windows\n\nWe will start up our services using a simple Bash script. Windows users should download [cygwin](http://www.cygwin.com/) \nto provide a command-line functionality similar to a Linux distribution on Windows.\n\n# Start Up\n\nBefore you start you should ensure that you have obtained or built the necessary Docker images locally. Please clone the \nrepository and create the necessary images by running the commands as shown:\n\n``` console\ngit clone https://github.com/FIWARE/tutorials.IoT-over-MQTT.git\ncd tutorials.IoT-over-MQTT\ngit checkout NGSI-v2\n./services create\n\n```\n\nThereafter, all services can be initialized from the command-line by running the \n[services](https://github.com/FIWARE/tutorials.IoT-over-MQTT/blob/NGSI-v2/services) Bash script provided within the \nrepository:\n\n``` console\n./services start\n\n```\n\n> :information_source: **Note:** If you want to clean up and start over again you can do so with the following command:\n> \n> ``` console\n> ./services stop\n> \n> ```\n\n## Provisioning Devices\n\nProvisioning devices is not the focus of this tutorial, and all the necessary device provisioning occurs automatically \nwhen the tutorial is started. However, for completeness the provisioning requests are repeated here and described below. \nIt is not necessary to re-run these commands.\n\nA series of service groups are created to associate classes of devices to an API Key, in the example below services have \nbeen created for `type=Bell` and `type=Motion`. It should be noted that the `resource` attribute has been left blank and \nthe `transport` set to `MQTT` - this is the same as the in the previous MQTT tutorial, since the IoT Agent is merely \nsending messsages to the MQTT broker and has no idea that a custom gateway component is also involved.\n\n``` bash\ncurl -X POST \\\n \"http://localhost:4041/iot/services\" \\\n -H 'Content-Type: application/json' \\\n -H 'fiware-service: openiot' \\\n -H 'fiware-servicepath: /' \\\n -d '{\n \"services\": [\n {\n \"apikey\": \"1068318794\",\n \"cbroker\": \"'\"http://orion:1026\"'\",\n \"entity_type\": \"Motion\",\n \"resource\": \"\",\n \"protocol\": \"PDI-IoTA-UltraLight\",\n \"transport\": \"MQTT\",\n \"timezone\": \"Europe/Berlin\",\n \"attributes\": [\n {\"object_id\": \"c\", \"name\":\"count\", \"type\":\"Integer\"},\n {\"object_id\": \"t\", \"name\": \"TimeInstant\", \"type\":\"DateTime\"}\n ],\n \"static_attributes\": [\n {\"name\": \"category\", \"type\":\"Text\", \"value\": [\"sensor\"]},\n {\"name\": \"controlledProperty\", \"type\": \"Text\", \"value\": \"motion\"},\n {\"name\": \"function\", \"type\": \"Text\", \"value\":[\"sensing\"]},\n {\"name\": \"supportedProtocol\", \"type\": \"Text\", \"value\": [\"ul20\"]},\n {\"name\": \"supportedUnits\", \"type\": \"Text\", \"value\": \"C62\"}\n ]\n },\n {\n \"apikey\": \"3020035\",\n \"cbroker\": \"'\"http://orion:1026\"'\",\n \"entity_type\": \"Bell\",\n \"resource\": \"\",\n \"protocol\": \"PDI-IoTA-UltraLight\",\n \"transport\": \"MQTT\",\n \"timezone\": \"Europe/Berlin\",\n \"commands\": [\n {\n \"name\": \"ring\",\n \"type\": \"command\"\n }\n ],\n \"static_attributes\": [\n {\"name\": \"category\", \"type\":\"Text\", \"value\": [\"actuator\"]},\n {\"name\": \"controlledProperty\", \"type\": \"Text\", \"value\": \"noiseLevel\"},\n {\"name\": \"function\", \"type\": \"Text\", \"value\":[\"onOff\"]},\n {\"name\": \"supportedProtocol\", \"type\": \"Text\", \"value\": [\"ul20\"]}\n ]\n }\n ]\n}'\n\n```\n\nCommands and measures defined when individual devices are provisioned. Once again the `transport` is set to MQTT.\n\n``` bash\ncurl -X POST \\\n \"http://localhost:4041/iot/devices\" \\\n -H 'Content-Type: application/json' \\\n -H 'fiware-service: openiot' \\\n -H 'fiware-servicepath: /' \\\n -d '{\n \"devices\": [\n {\n \"device_id\": \"motion001\",\n \"entity_name\": \"urn:ngsi-ld:Motion:001\",\n \"entity_type\": \"Motion\",\n \"transport\": \"MQTT\",\n \"static_attributes\": [\n {\"name\": \"refStore\", \"type\": \"Relationship\",\"value\": \"urn:ngsi-ld:Store:001\"}\n ]\n },\n {\n \"device_id\": \"bell001\",\n \"entity_name\": \"urn:ngsi-ld:Bell:001\",\n \"entity_type\": \"Bell\",\n \"transport\": \"MQTT\",\n \"static_attributes\": [\n {\"name\": \"refStore\", \"type\": \"Relationship\",\"value\": \"urn:ngsi-ld:Store:001\"}\n ]\n }\n ]\n}\n'\n\n```\n\n#### Device Monitor\n\nThe device monitor can be found at: `http://localhost:3000/device/monitor` - open the webpage to view the state of the \ndevices and view the persisted IOTA Tangle traffic.\n\n### Display the IOTA-Gateway logs (1st Terminal)\n\nOpen a **new terminal**, and follow the `iota-gateway` Docker container as follows:\n\n``` console\ndocker logs -f iota-gateway\n\n```\n\nThe terminal will then be ready to display received messages\n\n#### 1st terminal - Gateway Result:\n\nIf the MQTT-IOTA Gateway is functioning correctly, the following messages should be displayed\n\n``` txt\n2021-12-07T15:28:42.855Z gateway:app connected to IOTA Tangle: https://chrysalis-nodes.iota.cafe\n2021-12-07T15:28:42.862Z gateway:app Subscribing to 'messages/indexation/fiware/attrs'\n2021-12-07T15:28:42.872Z gateway:app Subscribing to 'messages/indexation/fiware/cmdexe'\n\n```\n\nThe gateway needs to subscribe to the IOTA Tangle to receive measures and command acknowledgements.\n\n### Display the Dummy Device logs (2nd Terminal)\n\nA sensor sending northbound measurements will persists transactions to the IOTA Tangle to which will be passed on to any \nsubscriber that wants them. The sensor does not need to make a connection to the subscriber directly. Similarly any \nconnected actuators will need to subscribe to an IOTA Tangle message topic to receive any commands that are relevant to \nthem.\n\nOpen a **new terminal**, and run a `fiware-tutorial` Docker container to send a message as follows:\n\n``` console\ndocker logs -f fiware-tutorial\n\n```\n\nThe terminal will then be ready to display received messages\n\n#### 2nd terminal - Device Result:\n\nIf the Devices are functioning correctly, the message should be received in the other terminal\n\n```\n2021-12-07T15:29:22.163Z tutorial:server Listening on port 3000\n2021-12-07T15:29:22.166Z tutorial:server Listening on port 3001\n2021-12-07T15:29:22.522Z tutorial:application MongoDB is connected.\n2021-12-07T15:29:22.612Z tutorial:iot-device connected to IOTA Tangle: https://chrysalis-nodes.iota.cafe\n2021-12-07T15:29:22.613Z tutorial:iot-device Subscribing to 'messages/indexation/fiware/cmd'\n\n```",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
{
"name": "Using the IOTA Tangle as a Transport",
"item": [
{
"name": "Sending Device Commands",
"request": {
"method": "PATCH",
"header": [
{
"key": "fiware-service",
"value": "openiot",
"type": "text"
},
{
"key": "fiware-servicepath",
"value": "/",
"type": "text"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"ring\": {\n \"type\" : \"command\",\n \"value\" : \"\"\n }\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "http://{{orion}}/v2/entities/urn:ngsi-ld:Bell:001/attrs",
"protocol": "http",
"host": [
"{{orion}}"
],
"path": [
"v2",
"entities",
"urn:ngsi-ld:Bell:001",
"attrs"
]
},
"description": "Since all the devices have been pre-provisioned, a bell can be rung using a standard NGSI-v2 PATCH request\n\nThe NGSI request is transformed into an MQTT message (with an Ultralight payload) which is received by the MQTT-IOTA \nGateway - this message is then persisted to the IOTA Tangle as shown:\n\n#### 1st terminal - Gateway Result:\n\n``` plaintext\n2021-12-07T15:50:54.848Z gateway:southbound Command received from MQTT bell001@ring|\n2021-12-07T15:51:12.580Z gateway:southbound Command pushed to Tangle: i=bell001&k=1068318794&d=bell001@ring| to fiware/cmd\n2021-12-07T15:51:12.581Z gateway:southbound messageId: 40431e6e39ade9babe02ef342ee9267f69982fe42db8f5d3f32d57bb686120d5\n\n```\n\nThe dummy device is also subscribing to IOTA Tangle messages, a message is received and the device is activated (in this \ncase the bell will ring). At this point an acknowledgement is placed onto the `fiware/cmdexe` topic:\n\n#### 2nd terminal - Device Result:\n\n``` plaintext\n2021-12-07T15:51:12.583Z tutorial:iot-device IOTA Tangle message received: 40431e6e39ade9babe02ef342ee9267f69982fe42db8f5d3f32d57bb686120d5\n2021-12-07T15:51:17.806Z tutorial:ultralight command response sent to fiware/cmdexe\n2021-12-07T15:51:17.806Z tutorial:ultralight 960e8ac4a9e22e360f7e92c3a7b9ac3b71c59950fd2fba7f4be551f930342f94\n2021-12-07T15:51:17.812Z tutorial:devices actuateDevice: bell001 ring\n\n```\n\nIf you are viewing the device monitor page, you can also see the state of the bell change.\n\n![](https://fiware.github.io//tutorials.IoT-over-IOTA/img/bell-ring.gif)\n\nThe Gateway receives the acknowledgement from the IOTA Tangle `fiware/cmdexe` topic and returns the result of the \nrequest to the IoT Agent.\n\n#### 1st terminal - Gateway Result:\n\n``` plaintext\n2021-12-07T15:51:18.022Z gateway:northbound Command response received from Tangle: i=bell001&k=1068318794&d=bell001@ring| ring OK\n2021-12-07T15:51:18.027Z gateway:northbound Sent to MQTT topic /1068318794/bell001/cmdexe\n2021-12-07T15:51:34.741Z gateway:northbound Command response received from Tangle: i=bell001&k=1068318794&d=bell001@ring| ring OK\n\n```"
},
"response": []
},
{
"name": "Get Device State",
"protocolProfileBehavior": {
"disableBodyPruning": true
},
"request": {
"method": "GET",
"header": [
{
"key": "fiware-service",
"value": "openiot",
"type": "text"
},
{
"key": "fiware-servicepath",
"value": "/",
"type": "text"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"ring\": {\n \"type\" : \"command\",\n \"value\" : \"\"\n }\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "http://{{orion}}/v2/entities/urn:ngsi-ld:Bell:001?options=keyValues",
"protocol": "http",
"host": [
"{{orion}}"
],
"path": [
"v2",
"entities",
"urn:ngsi-ld:Bell:001"
],
"query": [
{
"key": "options",
"value": "keyValues"
}
]
},
"description": "A measure from a device can be simulated by selecting **Detect Motion** from the dropdown and clicking on send.\n\n![](https://fiware.github.io//tutorials.IoT-over-IOTA/img/device-tangle.png)\n\nThe device persists the measure to the `fiware/attrs` topic on the IOTA Tangle Mainnet.\n\n#### 2nd terminal - Device Result:\n\n``` plaintext\n2021-12-07T16:34:25.767Z tutorial:devices fireMotionSensor\n2021-12-07T16:34:26.185Z tutorial:northbound sendIOTAMeasure: motion001\n2021-12-07T16:34:26.479Z tutorial:ultralight measure sent to fiware/attrs\n2021-12-07T16:34:26.479Z tutorial:ultralight da4df31054df529a3ade74befb84edabf7697ae8a3a9ee3481be08ee0aabb3e7\n\n```\n\nOnce the transactions is settled, it is passed onto the subscribing Gateway component\n\n#### 1st terminal - Gateway Result:\n\n``` plaintext\n2021-12-07T16:35:25.679Z gateway:northbound Measure received from Tangle: i=motion001&k=1068318794&d=c|0|t|2021-12-07T16:34:44.891Z\n2021-12-07T16:35:25.680Z gateway:northbound Sent to MQTT topic /1068318794/motion001/attrs\n\n```\n\nThere may be a noticable lag between reading the measure and it being received at the context broker. The payload of the \nmeasure therefore contains a timestamp `t|2021-12-07T16:34:44.891Z` which is mapped to `TimeInstant` in the IoT Agent to \nensure that the correct metadata is associated with the measure in the context broker.\n\nThe state of the sensor can be read by querying the entity within the Orion Context Broker."
},
"response": []
},
{
"name": "Sending Device Measures",
"protocolProfileBehavior": {
"disableBodyPruning": true
},
"request": {
"method": "GET",
"header": [
{
"key": "fiware-service",
"value": "openiot",
"type": "text"
},
{
"key": "fiware-servicepath",
"value": "/",
"type": "text"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"ring\": {\n \"type\" : \"command\",\n \"value\" : \"\"\n }\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "http://{{orion}}/v2/entities/urn:ngsi-ld:Bell:001?options=keyValues",
"protocol": "http",
"host": [
"{{orion}}"
],
"path": [
"v2",
"entities",
"urn:ngsi-ld:Bell:001"
],
"query": [
{
"key": "options",
"value": "keyValues"
}
]
},
"description": "The result of the command to ring the bell can be read by querying the entity within the Orion Context Broker.\n\nThe `TimeInstant` shows last the time any command associated with the entity has been invoked. The result of `ring` \ncommand can be seen in the value of the `ring_info` attribute.\n\n> **Note:** IOTA Transactions are not instantaneous, if the bell is queried before the transaction is complete, the \n> response will leave the `ring_status` as `PENDING`\n> \n> ``` json\n> {\n> \"id\": \"urn:ngsi-ld:Bell:001\",\n> \"type\": \"Bell\",\n> \"TimeInstant\": \"2021-12-07T15:51:36.219Z\",\n> \"category\": [ \"actuator\" ],\n> \"controlledProperty\": \"noiseLevel\",\n> \"function\": [ \"onOff\" ],\n> \"refStore\": \"urn:ngsi-ld:Store:001\",\n> \"ring_info\": \"UNKNOWN\",\n> \"ring_status\": \"PENDING\",\n> \"supportedProtocol\": [ \"ul20\" ],\n> \"ring\": \"\"\n> }\n> \n> ```\n\nFurthermore all transactions can be found on the IOTA Tangle under \n`https://explorer.iota.org/mainnet/message/`, for example \n`https://explorer.iota.org/mainnet/message/40431e6e39ade9babe02ef342ee9267f69982fe42db8f5d3f32d57bb686120d5` permanently \nholds the following data:\n\n![](https://fiware.github.io//tutorials.IoT-over-IOTA/img/mainnet.png)\n\nWhich indicates a request was sent to ring the bell."
},
"response": []
}
],
"description": "The IoT Agent acts as a middleware between the IoT devices and the context broker. It therefore\nneeds to be able to create context data entities with unique ids. Once a service has been provisioned\nand an unknown device makes a measurement the IoT Agent add this to the context using the supplied\n`<device-id>` (unless the device is recognized and can be mapped to a known id.\n\nThere is no guarantee that every supplied IoT device `<device-id>` will always be unique, therefore \nall provisioning requests to the IoT Agent require two mandatory headers:\n\n* `fiware-service` header is defined so that entities for a given service can be held in a separate mongoDB database.\n* `fiware-servicepath` can be used to differenciate between arrays of devices. \n\nFor example within a smart city application you would expect different `fiware-service` headers for different\ndepartments (e.g. parks, transport, refuse collection etc.) and each `fiware-servicepath` would refer to specific park \nand so on. This would mean that data and devices for each service can be identified and separated as needed, but the\ndata would not be siloed - for example data from a **Smart Bin** within a park can be combined with the **GPS Unit** \nof a refuse truck to alter the route of the truck in an efficient manner. \n\nThe **Smart Bin** and **GPS Unit** are likely to come from different manufacturers and it cannot be \nguaranteed that that there is no overlap within `<device-ids>`s used. The use of the `fiware-service` and\n`fiware-servicepath` headers can ensure that this is always the case, and allows the context broker to identify\nthe original source of the context data.\n",
"event": [
{
"listen": "prerequest",
"script": {
"type": "text/javascript",
"exec": [
""
]
}
},
{
"listen": "test",
"script": {
"type": "text/javascript",
"exec": [
""
]
}
}
]
},
{
"name": "MQTT-IOTA Gateway - Sample Code",
"item": [],
"description": "The [MQTT-IOTA Gateway](https://github.com/FIWARE/tutorials.IoT-over-IOTA/tree/master/iota-gateway/app) is a simple \napplication written in Node.js. Its only function is passing data between the two transports. MQTT Client libraries \nalready exist so the application can be set up to listen to the normal MQTT topic for IoT Agent actuations.\n\n``` javascript\nconst mqtt = require(\"mqtt\");\nconst MQTT_CLIENT = mqtt.connect(\"mqtt://mosquitto\");\nMQTT_CLIENT.on(\"connect\", () => {\n MQTT_CLIENT.subscribe(\"/+/+/cmd\");\n});\nMQTT_CLIENT.on(\"message\", Southbound.command);\n\n```\n\nSimilarly there are equivalent [client libraries](https://wiki.iota.org/iota.rs/libraries/nodejs/getting_started) \navailable in multiple langauges for persisting and listening to changes on the IOTA Tangle. The MQTT-IOTA Gateway needs \nto listen on two topics - one for device measures and a second one for acknowledgements of commands:\n\n``` javascript\nconst iotaClient = require(\"@iota/client\");\nconst IOTA_CLIENT = new iotaClient.ClientBuilder().node(\"https://chrysalis-nodes.iota.cafe\").build();\nIOTA_CLIENT.getInfo()\n .then(() => {\n IOTA_CLIENT.subscriber()\n .topic(IOTA_MESSAGE_INDEX + \"messages/indexation/fiware/attrs\")\n .subscribe((err, data) => {\n const messageId = IOTA_CLIENT.getMessageId(data.payload);\n IOTA_CLIENT.getMessage()\n .data(messageId)\n .then((messageData) => {\n Northbound.measure(messageData);\n });\n });\n IOTA_CLIENT.subscriber()\n .topic(IOTA_MESSAGE_INDEX + \"messages/indexation/fiware/cmdexe\")\n .subscribe((err, data) => {\n const messageId = IOTA_CLIENT.getMessageId(data.payload);\n IOTA_CLIENT.getMessage()\n .data(messageId)\n .then((messageData) => {\n Northbound.commandResponse(messageData);\n });\n });\n })\n .catch((err) => {\n debug(err);\n });\n\n```\n\n### MQTT-IOTA Gateway Southbound - Sample Code\n\nFor the southbound traffic, the API Key and device id are extracted from the MQTT topic and moved into the IOTA payload. \nThe syntax of the IOTA payload (with `i`, `k` and `d` attributes) is based on the \n[Ultralight HTTP syntax](https://fiware-iotagent-ul.readthedocs.io/en/latest/usermanual/index.html#http-binding). The \n`message` is then persisted to the Tangle using an appropriate index:\n\n``` javascript\nfunction command(topic = \"cmd\", message) {\n const parts = topic.toString().split(\"/\");\n const apiKey = parts[1];\n const deviceId = parts[2];\n const action = parts[3];\n forwardAsIOTATangle(apiKey, deviceId, message.toString(), action);\n}\nfunction forwardAsIOTATangle(apiKey, deviceId, state, topic) {\n const payload = \"i=\" + deviceId + \"&k=\" + apiKey + \"&d=\" + state;\n IOTA_CLIENT.message()\n .index(\"fiware/\" + topic)\n .data(payload)\n .submit()\n .then((message) => {\n debug(\"messageId: \" + message.messageId);\n });\n}\n\n```\n\n### MQTT-IOTA Gateway Northbound - Sample Code\n\nNorthbound traffic is similar - the payload is received from the IOTA Tangle, unmarshalled to reveal the API Key and \ndevice id, and the posted to an appropriate MQTT Topic.\n\n``` javascript\nfunction unmarshall(payload) {\n const parts = payload.split(\"&\");\n const obj = {};\n parts.forEach((elem) => {\n const keyValues = elem.split(\"=\");\n obj[keyValues[0]] = keyValues[1];\n });\n return obj;\n}\nfunction measure(messageData) {\n const payload = Buffer.from(messageData.message.payload.data, \"hex\").toString(\"utf8\");\n const data = unmarshall(payload);\n forwardAsMQTT(data.k, data.i, data.d, \"attrs\");\n}\nfunction forwardAsMQTT(apiKey, deviceId, state, topic) {\n const mqttTopic = \"/\" + apiKey + \"/\" + deviceId + \"/\" + topic;\n MQTT_CLIENT.publish(mqttTopic, state);\n}\n\n```\n\nThe [full code](https://github.com/FIWARE/tutorials.IoT-over-IOTA/tree/master/iota-gateway/app) of the MQTT-IOTA Gateway \nincludes additional error handling and asynchronous data handling to defer the execution of a function until the next \nEvent Loop iteration.",
"event": [
{
"listen": "prerequest",
"script": {
"type": "text/javascript",
"exec": [
""
]
}
},
{
"listen": "test",
"script": {
"type": "text/javascript",
"exec": [
""
]
}
}
]
},
{
"name": "IOTA Tangle Device - Sample Code",
"item": [],
"description": "The code for a device to connect to the IOTA Tangle is repeated on the device. Actuators must listen to an agreed topic \nin order to be informed of commands. `process.nextTick()` can be used to ensure commands are not missed and can be \nprocessed when time permits.\n\n``` javascript\nconst iotaClient = require(\"@iota/client\");\nconst IOTA_CLIENT = new iotaClient.ClientBuilder().node(\"https://chrysalis-nodes.iota.cafe\").build();\nIOTA_CLIENT.getInfo().then(() => {\n IOTA_CLIENT.subscriber()\n .topic(\"messages/indexation/cmd\")\n .subscribe((err, data) => {\n return process.nextTick(() => {\n readFromTangle(data);\n });\n });\n});\nfunction readFromTangle(data) {\n const messageId = IOTA_CLIENT.getMessageId(payload);\n IOTA_CLIENT.getMessage()\n .data(messageId)\n .then((messageData) => {\n const payload = Buffer.from(messageData.message.payload.data, \"hex\").toString(\"utf8\");\n Southbound.processIOTAMessage(messageId, payload);\n });\n}\n\n```\n\n### IOTA Tangle Device Command Acknowledgement\n\nFor real devices, the callback of a successful actuation should cause an acknowledgement to be sent. Acknowledgements \nare queued and sent in order. If an error occurs the acknowledgement must be resent or the command will remain in a \n`PENDING` state.\n\n``` javascript\n processIOTAMessage(apiKey, deviceId, message) {\n const keyValuePairs = message.split('|') || [''];\n const command = getUltralightCommand(keyValuePairs[0]);\n process.nextTick(() => {\n IoTDevices.actuateDevice(deviceId, command)\n .then((response) => {\n queue.push({ responsePayload, deviceId, command });\n });\n });\n }\n\n```\n\n``` javascript\nconst async = require(\"async\");\nconst queue = async.queue((data, callback) => {\n IOTA_CLIENT.message()\n .index(\"fiware/cmdexe\")\n .data(data.responsePayload)\n .submit()\n .then((response) => {\n callback();\n })\n .catch((err) => {\n setTimeout(() => {\n queue.push(data);\n }, 1000);\n callback(err);\n }, 8);\n});\n\n```\n\n### IOTA Tangle Device measure - Sample Code\n\nMeasures are dealt with in a similar manner. The payload is created in Ultralight syntax (including a timestamp) and \npushed to a queue. The queue sends the measure to the IOTA Tangle and reschedules any failures.\n\n``` javascript\nsendAsIOTA(deviceId, state) {\n const payload =\n 'i=' + deviceId + '&k=' + getAPIKey(deviceId) + '&d=' + state + '|t|' + new Date().toISOString();\n queue.push(payload);\n}\n\n```\n\n``` javascript\nconst async = require(\"async\");\nconst queue = async.queue((payload, callback) => {\n IOTA_CLIENT.message()\n .index(\"fiware/attrs\")\n .data(payload)\n .submit()\n .then((message) => {\n callback();\n })\n .catch((err) => {\n setTimeout(() => {\n // resending measure\n queue.push(payload);\n }, 1000);\n callback(err);\n }, 8);\n});\n\n```",
"event": [
{
"listen": "prerequest",
"script": {
"type": "text/javascript",
"exec": [
""
]
}
},
{
"listen": "test",
"script": {
"type": "text/javascript",
"exec": [
""
]
}
}
]
}
],
"event": [
{
"listen": "prerequest",
"script": {
"type": "text/javascript",
"exec": [
""
]
}
},
{
"listen": "test",
"script": {
"type": "text/javascript",
"exec": [
""
]
}
}
],
"variable": [
{
"key": "iot-agent",
"value": "localhost:4041",
"type": "string"
},
{
"key": "orion",
"value": "localhost:1026",
"type": "string"
},
{
"key": "ultralight",
"value": "localhost:3001",
"type": "string"
}
]
}