Skip to content

Commit

Permalink
Merge pull request #8 from FIWARE/feature/mqtt-protocol
Browse files Browse the repository at this point in the history
Prepend MQTT protocol to MQTT topics
  • Loading branch information
jason-fox authored Apr 27, 2022
2 parents d2d0d48 + bce51ad commit 6ac7020
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 17 deletions.
6 changes: 3 additions & 3 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npm run pre-commit
#npm run pre-commit

cd context-provider
npm run pre-commit
#cd context-provider
#npm run pre-commit
8 changes: 7 additions & 1 deletion context-provider/controllers/iot/command-listener.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ const DEVICE_VERSION = process.env.DEVICE_VERSION || NGSI_VERSION;
const NGSI_PREFIX = process.env.NGSI_LD_PREFIX !== undefined ? process.env.NGSI_LD_PREFIX : 'urn:ngsi-ld:';
const AUTHZFORCE_ENABLED = process.env.AUTHZFORCE_ENABLED || false;

const port = process.env.WEB_APP_PORT || '3000';
const dataModelContext =
process.env.IOTA_JSON_LD_CONTEXT || 'http://localhost:' + port + '/data-models/ngsi-context.jsonld';

function createNGSIv2Request(action, id) {
const method = 'PATCH';
const body = {};
Expand Down Expand Up @@ -48,7 +52,8 @@ function createNGSILDRequest(action, id) {
'NGSILD-Tenant': 'openiot',
'NGSILD-Path': '/',
'fiware-service': 'openiot',
'fiware-servicepath': '/'
'fiware-servicepath': '/',
Link: '<' + dataModelContext + '>; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json"'
};

return { method, url, headers, body, json: true };
Expand Down Expand Up @@ -89,6 +94,7 @@ function sendCommand(req, res) {
options.headers['X-Auth-Token'] = req.session.access_token;
}

debug(JSON.stringify(options, null, 4));
request(options, (error) => {
if (error) {
debug(error);
Expand Down
5 changes: 5 additions & 0 deletions context-provider/iot.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const logger = require('morgan');
/* global MQTT_CLIENT */
/* global IOTA_CLIENT */
const DEVICE_TRANSPORT = process.env.DUMMY_DEVICES_TRANSPORT || 'HTTP';
const MQTT_TOPIC_PROTOCOL = process.env.MQTT_TOPIC_PROTOCOL || 'ul';

const MQTT_BROKER_URL = process.env.MQTT_BROKER_URL || 'mqtt://mosquitto';
global.MQTT_CLIENT = mqtt.connect(MQTT_BROKER_URL);
Expand Down Expand Up @@ -62,6 +63,10 @@ if (DEVICE_TRANSPORT === 'MQTT') {
debug('Subscribing to MQTT Broker: ' + MQTT_BROKER_URL + ' ' + topic);
MQTT_CLIENT.subscribe(topic);
MQTT_CLIENT.subscribe(topic + '/#');
if (process.env.MQTT_TOPIC_PROTOCOL !== '') {
MQTT_CLIENT.subscribe('/' + MQTT_TOPIC_PROTOCOL + topic);
MQTT_CLIENT.subscribe('/#' + MQTT_TOPIC_PROTOCOL + topic + '/#');
}
});
});

Expand Down
6 changes: 5 additions & 1 deletion context-provider/models/measure/json.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const async = require('async');

const DEVICE_API_KEY = process.env.DUMMY_DEVICES_API_KEY || '1234';
const IOTA_ATTRS_TOPIC = (process.env.IOTA_MESSAGE_INDEX || 'fiware') + '/attrs';
const MQTT_TOPIC_PROTOCOL = process.env.MQTT_TOPIC_PROTOCOL || 'json';

// URL for Devices using the HTTP transport
const IOT_AGENT_URL =
Expand Down Expand Up @@ -120,7 +121,10 @@ class JSONMeasure {

// measures sent over MQTT are posted as topics (motion sensor, lamp and door)
sendAsMQTT(deviceId, state) {
const topic = '/' + getAPIKey(deviceId) + '/' + deviceId + '/attrs';
let topic = '/' + getAPIKey(deviceId) + '/' + deviceId + '/attrs';
if (process.env.MQTT_TOPIC_PROTOCOL !== '') {
topic = '/' + MQTT_TOPIC_PROTOCOL + topic;
}
MQTT_CLIENT.publish(topic, ultralightToJSON(state));
}

Expand Down
6 changes: 5 additions & 1 deletion context-provider/models/measure/ultralight.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const DEVICE_API_KEY = process.env.DUMMY_DEVICES_API_KEY || '1234';

// Message Topic for Devices using the IOTA Tangle transport
const IOTA_ATTRS_TOPIC = (process.env.IOTA_MESSAGE_INDEX || 'fiware') + '/attrs';
const MQTT_TOPIC_PROTOCOL = process.env.MQTT_TOPIC_PROTOCOL || 'ul';

// URL for Devices using the HTTP transport
const IOT_AGENT_URL =
Expand Down Expand Up @@ -111,7 +112,10 @@ class UltralightMeasure {

// measures sent over MQTT are posted as topics (motion sensor, lamp and door)
sendAsMQTT(deviceId, state) {
const topic = '/' + getAPIKey(deviceId) + '/' + deviceId + '/attrs';
let topic = '/' + getAPIKey(deviceId) + '/' + deviceId + '/attrs';
if (process.env.MQTT_TOPIC_PROTOCOL !== '') {
topic = '/' + MQTT_TOPIC_PROTOCOL + topic;
}
MQTT_CLIENT.publish(topic, state);
}

Expand Down
6 changes: 5 additions & 1 deletion context-provider/models/measure/xml.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const debug = require('debug')('tutorial:xml');

const DEVICE_API_KEY = process.env.DUMMY_DEVICES_API_KEY || '1234';
const IOTA_ATTRS_TOPIC = (process.env.IOTA_MESSAGE_INDEX || 'fiware') + '/attrs';
const MQTT_TOPIC_PROTOCOL = process.env.MQTT_TOPIC_PROTOCOL || 'xml';

const IOT_AGENT_URL =
'http://' +
Expand Down Expand Up @@ -83,7 +84,10 @@ class XMLMeasure {

// measures sent over MQTT are posted as topics (motion sensor, lamp and door)
sendAsMQTT(deviceId, state) {
const topic = '/' + getAPIKey(deviceId) + '/' + deviceId + '/attrs';
let topic = '/' + getAPIKey(deviceId) + '/' + deviceId + '/attrs';
if (process.env.MQTT_TOPIC_PROTOCOL !== '') {
topic = '/' + MQTT_TOPIC_PROTOCOL + topic;
}
MQTT_CLIENT.publish(topic, ultralightToXML(DEVICE_API_KEY, deviceId, state));
}
// measures sent over IOTA are posted as topics (motion sensor, lamp and door)
Expand Down
34 changes: 25 additions & 9 deletions docs/iot-over-mqtt.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ dependencies between the data producers and the data consumers.
A summary of the differences between the two transport protocols can be seen below:

| HTTP Transport | MQTT Transport |
|-------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------|
| ----------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| ![](https://fiware.github.io/tutorials.IoT-over-MQTT/img/http.png) | ![](https://fiware.github.io/tutorials.IoT-over-MQTT/img/mqtt.png) |
| IoT Agent communicates with IoT devices **directly** | IoT Agent communicates with IoT devices **indirectly** via an MQTT Broker |
| [Request-Response](https://en.wikipedia.org/wiki/Request%E2%80%93response) Paradigm | [Publish-Subscribe](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern) Paradigm |
Expand Down Expand Up @@ -175,7 +175,7 @@ The `tutorial` container is listening on two ports:
The `tutorial` container is driven by environment variables as shown:

| Key | Value | Description |
|-------------------------|------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------|
| ----------------------- | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| DEBUG | `tutorial:*` | Debug flag used for logging |
| WEB_APP_PORT | `3000` | Port used by web-app which displays the dummy device data |
| DUMMY_DEVICES_PORT | `3001` | Port used by the dummy IoT devices to receive commands |
Expand Down Expand Up @@ -229,7 +229,7 @@ information such as device URLs and Keys. The container is listening on a single
The `iot-agent` container is driven by environment variables as shown:

| Key | Value | Description |
|----------------------|-------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------|
| -------------------- | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| IOTA_CB_HOST | `orion` | Hostname of the context broker to update context |
| IOTA_CB_PORT | `1026` | Port that context broker listens on to update context |
| IOTA_NORTH_PORT | `4041` | Port used for Configuring the IoT Agent and receiving context updates from the context broker |
Expand All @@ -253,7 +253,7 @@ As you can see, use of the MQTT transport is driven by only two environment vari
Before you start you should ensure that you have obtained or built the necessary Docker images locally. Please clone the
repository and create the necessary images by running the commands as shown:

``` bash
```bash
#!/bin/bash
git clone https://github.com/FIWARE/tutorials.IoT-over-MQTT.git
cd tutorials.IoT-over-MQTT
Expand Down Expand Up @@ -419,8 +419,8 @@ The response will look similar to the following:

The IoT Agent acts as a middleware between the IoT devices and the context broker. It therefore needs to be able to
create context data entities with unique IDs. Once a service has been provisioned and an unknown device makes a
measurement, the IoT Agent add this to the context using the supplied `<device-id>`, unless the device is recognized
and can be mapped to a known ID.
measurement, the IoT Agent add this to the context using the supplied `<device-id>`, unless the device is recognized and
can be mapped to a known ID.

There is no guarantee that every supplied IoT device `<device-id>` will always be unique, therefore all provisioning
requests to the IoT Agent require two mandatory headers:
Expand All @@ -447,7 +447,23 @@ It is possible to set up default commands and attributes for all devices as well
tutorial as we will be provisioning each device separately.

This example provisions an anonymous group of devices. It tells the IoT Agent that a series of devices will be
communicating by sending messages to the `/4jggokgpepnvsb2uv4s40d59ov` **topic**
communicating by sending device measures over the `/ul/4jggokgpepnvsb2uv4s40d59ov` **topic**

> **Note** Measures and commands are sent over different MQTT topics:
>
> * _Measures_ are sent on the `/<protocol>/<api-key>/<device-id>/attrs` topic,
> * _Commands_ are sent on the `/<api-key>/<device-id>/cmd` topic,
>
> The reasoning behind this is that when sending measures northbound from device to IoT Agent,
> it is necessary to explicitly identify which IoT Agent is needed to parse the data. This
> is done by prefixing the relevant MQTT topic with a protocol, otherwise there is no way to
> define which agent is processing the measure. This mechanism allows smart systems to connect
> different devices to different IoT Agents according to need.
>
> For southbound commands, this distinction is unnecessary since the correct IoT Agent has already
> registered itself for the command during the device provisioning step and the device will always
> receive commands in an appropriate format.


The `resource` attribute is left blank since HTTP communication is not being used.

Expand Down Expand Up @@ -535,7 +551,7 @@ message to the following **topic**
```bash
docker run -it --rm --name mqtt-publisher --network \
fiware_default efrecon/mqtt-client pub -h mosquitto -m "c|1" \
-t "/4jggokgpepnvsb2uv4s40d59ov/motion001/attrs"
-t "/ul/4jggokgpepnvsb2uv4s40d59ov/motion001/attrs"
```

- The value of the `-m` parameter defines the message. This is in UltraLight syntax.
Expand All @@ -544,7 +560,7 @@ docker run -it --rm --name mqtt-publisher --network \
The **topic** must be in the following form:

```text
/<api-key>/<device-id>/attrs
/<protocol>/<api-key>/<device-id>/attrs
```

> **Note** In the [previous tutorial](iot-agent.md), when testing HTTP connectivity between the Motion Sensor and an IoT
Expand Down
2 changes: 1 addition & 1 deletion tutorials.IoT-over-MQTT

0 comments on commit 6ac7020

Please sign in to comment.