# MQTT

[MQTT](https://mqtt.org/) (Message Queuing Telemetry Transport) is a lightweight and widely adopted messaging protocol well-suited for resource-constrained devices.

If a device communicates over **MQTT** with akenza, an MQTT data flow has to be set up.

### Endpoints

* `mqtts://mqtt.akenza.io:8883` (recommended)
* `wss://mqtt.akenza.io:443/mqtt`
* `mqtt://mqtt.akenza.io:1883` (unencrypted, not recommended)

### Authentication

There are two ways to authenticate: **device credentials with JWTs** use a per-device public/private key pair with JSON Web Tokens (JWTs, [RFC 7519](https://www.rfc-editor.org/rfc/rfc7519)) and **uplink secrets** use a shared key per device connector that is passed as a password to the MQTT broke&#x72;**.** The authentication type can be selected during creation of the device connector.&#x20;

Refer to [Device Security](/akenza.io/get-started/your-data-flow/device-connector/device-security.md) for a more in-depth introduction into the authentication options.

**Using device credentials**

Using the private key, a JWT has to be generated that is sent as the MQTT password when setting up connection to the akenza MQTT broker.

* MQTT username: arbitrary username (not used). Depending on framework this needs to be set in order for the password to be sent as well
* MQTT password: must be a valid JWT signed with the private key. Refer to [Using JSON Web Tokens (JWTs)](/akenza.io/get-started/your-data-flow/device-connector/device-security/using-device-credentials/using-json-web-tokens-jwts.md)
* MQTT client id: the `clientId` must be the deviceId
* MQTT topic: a topic with the following structure&#x20;
  * uplink topic: `/up/device/id/{deviceId}`
  * downlink topic: `/down/device/id/{deviceId}/#`

**Using uplink secret**

After the creation of the **MQTT device connecto**r, a secret is generated which needs to be provided in the topic structure of the uplink request.&#x20;

* MQTT username: the device connector id
* MQTT password: the device connector secret&#x20;
* MQTT topic: a topic with the following structure&#x20;
  * uplink topic: `/up/<deviceConnectorSecret>/id/<deviceID>`
  * downlink topic: `/up/<deviceConnectorSecret>/id/<deviceID>/#`

### Sending data with MQTT

{% code title="uplink.py" %}

```python
import paho.mqtt.publish as publish

topic ="<copy from Akenza Device Api configuration>"
host = "mqtt.akenza.io"
mqtt_username = "<copy from Akenza Device Api configuration>"
mqtt_password = "<copy from Akenza Device Api configuration>"
payload = '{"foo":"bar"}'

publish.single(topic, payload, hostname=host, port=1883, auth={'username':mqtt_username, 'password':mqtt_password})
```

{% endcode %}

```bash
pip3 install paho-mqtt
python3 uplink.py
```

#### MQTT Sub Topics

It is possible to additionally specify a sub topic by appending it to the uplink topic, e.g. `/up/device/id/{deviceId}/alerts` will result in the akenza topic `alerts`. The subtopic will be used as the topic under which data is stored in akenza and is available in the uplink decoder script of the device type. If multiple levels of subtopics are specified, the resulting topic will be separated by underscores, e.g. `/up/device/id/{deviceId}/alerts/critical` will result in `alerts_critical`.

### **Receiving Downlinks with MQTT**

Subscribing to downlinks is possible by providing the following info:

* MQTT username: the device connector id
* MQTT password: the device connector secret&#x20;
* MQTT topic: a topic with the following structure `/down/<deviceConnectorSecret>/id/<deviceID>`

{% code title="downlink.py" %}

```python
import paho.mqtt.client as mqtt
from paho.mqtt.client import error_string

host = "mqtt.akenza.io"
mqtt_username = "<copy from Akenza Device Api configuration>"
mqtt_password = "<copy from Akenza Device Api configuration>"
device_id= "<copy from Akenza Device Api configuration>"
topic = "/down/{0}/id/{1}/#".format(mqtt_password, device_id)

def on_connect(client, userdata, flags, rc):  # The callback for when the client connects to the broker
    print("Connected with result code {0}".format(error_string(rc)))

def on_message(client, userdata, message):
    print("Received message '" + str(message.payload) + "' on topic '"
        + message.topic + "' with QoS " + str(message.qos))

def on_disconnect(client, userdata, rc):
    print("Unexpected disconnection. " + error_string(rc))
    if rc != 0:
        print("Unexpected disconnection. " + error_string(rc))

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1, "mqtt-test-client")
client.username_pw_set(mqtt_username, mqtt_password)
client.on_message = on_message
client.on_connect = on_connect
client.on_disconnect = on_disconnect
client.connect(host, 1883)
client.subscribe(topic)  # Subscribe to the topic, receive any messages published on it

client.loop_forever()  # Start networking daemon
```

{% endcode %}

```
pip3 install paho-mqtt
python3 downlink.py
```

The downlink topic added in akenza will be appended to the topic subscribed to e.g. when providing "myTopic" the resulting downlink topic will look as follows: /down/{0}/id/{1}/myTopic.

{% hint style="info" %}
Use the [device configuration feature](https://docs.api.akenza.io/#330a150e-a7be-476b-90a8-050364477516) to receive a downlink with the newest configuration when connecting your device with akenza.
{% endhint %}

### Using TLS

akenza allows sending data using transport layer security (TLS). For this the port 8883 has to be used.

```python
import paho.mqtt.publish as publish
import ssl

topic ="<copy from Akenza Device Api configuration>"
host = "mqtt.akenza.io"
mqtt_username = "<copy from Akenza Device Api configuration>"
mqtt_password = "<copy from Akenza Device Api configuration>"
payload = '{"foo":"bar"}'

tls_config = {
    "cert_reqs": ssl.CERT_REQUIRED,
    "tls_version": ssl.PROTOCOL_TLSv1_2
}
publish.single(topic, payload, hostname=host, port=8883, tls = tls_config, auth={'username':mqtt_username, 'password':mqtt_password})
```

Refer to the [paho-mqtt ](https://pypi.org/project/paho-mqtt/)documentation for more information.

**Why am I getting a certificate expired error?**

Akenza is using an ISRG Root X1 root certificate provided by Let's Encrypt to sign certificates. If your device is older, it might not contain an up to date root certificate. Aquire the root certificate from [here](https://letsencrypt.org/certificates/) and update your trust store accordingly.

### Sending data with MQTT v5

```python
import paho.mqtt.client as client
import ssl

topic ="<copy from Akenza Device Api configuration>"
host = "mqtt.akenza.io"
mqtt_username = "<copy from Akenza Device Api configuration>"
mqtt_password = "<copy from Akenza Device Api configuration>"
payload = '{"foo":"bar"}'

tls_config = {
    "cert_reqs": ssl.CERT_REQUIRED,
    "tls_version": ssl.PROTOCOL_TLSv1_2
}

publish.single(topic, payload, hostname=host, port=8883, tls = tls_config, auth={'username':mqtt_username, 'password':mqtt_password}, protocol=client.MQTTv5)
```

### MQTT v5 Content Types

With MQTT v5 it is possible to send different content types by setting the ContentType property. The supported MIME types are:

* `application/json`
* `text/plain`
* `application/octet-stream`
* `application/xml`
* `text/csv`

If this property is not set, a published message will be interpreted as a JSON message.

```python
import paho.mqtt.client as client
from paho.mqtt.properties import Properties
from paho.mqtt.packettypes import PacketTypes 

topic ="<copy from Akenza Device Api configuration>"
host = "mqtt.akenza.io"
mqtt_username = "<copy from Akenza Device Api configuration>"
mqtt_password = "<copy from Akenza Device Api configuration>"
client_id = "<an arbitrary client id>"
payload = '<?xml version=\'1.0\' encoding=\'UTF-8\'?><data><foo>bar</foo></data>'

properties=Properties(PacketTypes.PUBLISH)
properties.ContentType="application/xml"

client = client.Client(client_id, protocol=mqtt_client.MQTTv5)
client.username_pw_set(username, password)
client.connect(host, port)

client.publish(topic, payload, properties=properties)
```

### Examples

A set of examples for using MQTT with akenza can be found here:

* [Java](https://github.com/akenza-io/akenza-java-examples/blob/main/src/main/java/io/akenza/examples/mqtt/MqttExample.java)
* [JavaScript](https://github.com/akenza-io/akenza-examples/blob/main/examples/uplink/mqtt-send-data-tls.mjs)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.akenza.io/akenza.io/get-started/your-data-flow/device-connector/mqtt.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
