Skip to content

Commit 21e995f

Browse files
committed
update MQTT Sink template
1 parent c1dd18c commit 21e995f

File tree

5 files changed

+312
-105
lines changed

5 files changed

+312
-105
lines changed

python/destinations/MQTT/README.md

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,18 @@ You'll need to have a MQTT either locally or in the cloud
2424
The connector uses the following environment variables:
2525

2626
- **input**: Name of the input topic to listen to.
27-
- **mqtt_topic_root**: The root for messages in MQTT, this can be anything.
28-
- **mqtt_server**: The address of your MQTT server.
29-
- **mqtt_port**: The port of your MQTT server.
30-
- **mqtt_username**: Username of your MQTT user.
31-
- **mqtt_password**: Password for the MQTT user.
27+
- **MQTT_CLIENT_ID**: A client ID for the sink.
28+
**Default**: `mqtt-sink`
29+
- **MQTT_TOPIC_ROOT**: The root for messages in MQTT, this can be anything.
30+
- **MQTT_SERVER**: The address of your MQTT server.
31+
- **MQTT_PORT**: The port of your MQTT server.
32+
**Default**: `8883`
33+
- **MQTT_USERNAME**: Username of your MQTT user.
34+
- **MQTT_PASSWORD**: Password for the MQTT user.
35+
- **MQTT_VERSION**: MQTT protocol version; choose 3.1, 3.1.1, or 5.
36+
**Default**: `3.1.1`
37+
- **MQTT_USE_TLS**: Set to true if the server uses TLS.
38+
**Default**: `True`
3239

3340
## Contribute
3441

python/destinations/MQTT/library.json

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,51 +18,65 @@
1818
"Type": "EnvironmentVariable",
1919
"InputType": "InputTopic",
2020
"Description": "Name of the input topic to listen to.",
21-
"DefaultValue": "",
2221
"Required": true
2322
},
2423
{
25-
"Name": "mqtt_topic_root",
24+
"Name": "MQTT_CLIENT_ID",
25+
"Type": "EnvironmentVariable",
26+
"InputType": "FreeText",
27+
"Description": "A client ID for the sink",
28+
"DefaultValue": "mqtt-sink",
29+
"Required": true
30+
},
31+
{
32+
"Name": "MQTT_TOPIC_ROOT",
2633
"Type": "EnvironmentVariable",
2734
"InputType": "FreeText",
2835
"Description": "The root for messages in MQTT, this can be anything",
2936
"Required": true
3037
},
3138
{
32-
"Name": "mqtt_server",
39+
"Name": "MQTT_SERVER",
3340
"Type": "EnvironmentVariable",
3441
"InputType": "FreeText",
3542
"Description": "The address of your MQTT server",
3643
"Required": true
3744
},
3845
{
39-
"Name": "mqtt_port",
46+
"Name": "MQTT_PORT",
4047
"Type": "EnvironmentVariable",
4148
"InputType": "FreeText",
4249
"Description": "The port of your MQTT server",
4350
"DefaultValue": "8883",
4451
"Required": true
4552
},
4653
{
47-
"Name": "mqtt_username",
54+
"Name": "MQTT_USERNAME",
4855
"Type": "EnvironmentVariable",
4956
"InputType": "FreeText",
5057
"Description": "Username of your MQTT user",
51-
"Required": false
58+
"Required": true
5259
},
5360
{
54-
"Name": "mqtt_password",
61+
"Name": "MQTT_PASSWORD",
5562
"Type": "EnvironmentVariable",
5663
"InputType": "Secret",
5764
"Description": "Password for the MQTT user",
58-
"Required": false
65+
"Required": true
66+
},
67+
{
68+
"Name": "MQTT_VERSION",
69+
"Type": "EnvironmentVariable",
70+
"InputType": "FreeText",
71+
"Description": "MQTT protocol version; choose 3.1, 3.1.1, or 5",
72+
"Required": true
5973
},
6074
{
61-
"Name": "mqtt_version",
75+
"Name": "MQTT_USE_TLS",
6276
"Type": "EnvironmentVariable",
6377
"InputType": "FreeText",
64-
"Description": "MQTT protocol version: 3.1, 3.1.1, 5",
65-
"DefaultValue": "3.1.1",
78+
"Description": "Set to true if the server uses TLS",
79+
"DefaultValue": "true",
6680
"Required": true
6781
}
6882
],

python/destinations/MQTT/main.py

Lines changed: 20 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,95 +1,28 @@
1-
from quixstreams import Application, context
2-
import paho.mqtt.client as paho
3-
from paho import mqtt
4-
import json
1+
from mqtt import MQTTSink
2+
from quixstreams import Application
53
import os
64

75
# Load environment variables (useful when working locally)
8-
from dotenv import load_dotenv
9-
load_dotenv()
6+
# from dotenv import load_dotenv
7+
# load_dotenv()
108

11-
def mqtt_protocol_version():
12-
if os.environ["mqtt_version"] == "3.1":
13-
print("Using MQTT version 3.1")
14-
return paho.MQTTv31
15-
if os.environ["mqtt_version"] == "3.1.1":
16-
print("Using MQTT version 3.1.1")
17-
return paho.MQTTv311
18-
if os.environ["mqtt_version"] == "5":
19-
print("Using MQTT version 5")
20-
return paho.MQTTv5
21-
print("Defaulting to MQTT version 3.1.1")
22-
return paho.MQTTv311
9+
app = Application(consumer_group="mqtt_consumer_group", auto_offset_reset="earliest")
10+
input_topic = app.topic(os.environ["input"], value_deserializer="double")
2311

24-
def configure_authentication(mqtt_client):
25-
mqtt_username = os.getenv("mqtt_username", "")
26-
if mqtt_username != "":
27-
mqtt_password = os.getenv("mqtt_password", "")
28-
if mqtt_password == "":
29-
raise ValueError('mqtt_password must set when mqtt_username is set')
30-
print("Using username & password authentication")
31-
mqtt_client.username_pw_set(os.environ["mqtt_username"], os.environ["mqtt_password"])
32-
return
33-
print("Using anonymous authentication")
12+
sink = MQTTSink(
13+
client_id=os.environ["MQTT_CLIENT_ID"],
14+
server=os.environ["MQTT_SERVER"],
15+
port=int(os.environ["MQTT_PORT"]),
16+
topic_root=os.environ["MQTT_TOPIC_ROOT"],
17+
username=os.environ["MQTT_USERNAME"],
18+
password=os.environ["MQTT_PASSWORD"],
19+
version=os.environ["MQTT_VERSION"],
20+
tls_enabled=os.environ["MQTT_USE_TLS"].lower() == "true"
21+
)
3422

35-
mqtt_port = os.environ["mqtt_port"]
36-
# Validate the config
37-
if not mqtt_port.isnumeric():
38-
raise ValueError('mqtt_port must be a numeric value')
23+
sdf = app.dataframe(topic=input_topic)
24+
sdf.sink(sink)
3925

40-
client_id = os.getenv("Quix__Deployment__Id", "default")
41-
mqtt_client = paho.Client(callback_api_version=paho.CallbackAPIVersion.VERSION2,
42-
client_id = client_id, userdata = None, protocol = mqtt_protocol_version())
43-
mqtt_client.tls_set(tls_version = mqtt.client.ssl.PROTOCOL_TLS) # we'll be using tls
44-
mqtt_client.reconnect_delay_set(5, 60)
45-
configure_authentication(mqtt_client)
4626

47-
# Create a Quix platform-specific application instead
48-
app = Application(consumer_group="mqtt_consumer_group", auto_offset_reset='earliest')
49-
# initialize the topic, this will combine the topic name with the environment details to produce a valid topic identifier
50-
input_topic = app.topic(os.environ["input"])
51-
52-
# setting callbacks for different events to see if it works, print the message etc.
53-
def on_connect_cb(client: paho.Client, userdata: any, connect_flags: paho.ConnectFlags,
54-
reason_code: paho.ReasonCode, properties: paho.Properties):
55-
if reason_code == 0:
56-
print("CONNECTED!") # required for Quix to know this has connected
57-
else:
58-
print(f"ERROR! - ({reason_code.value}). {reason_code.getName()}")
59-
60-
def on_disconnect_cb(client: paho.Client, userdata: any, disconnect_flags: paho.DisconnectFlags,
61-
reason_code: paho.ReasonCode, properties: paho.Properties):
62-
print(f"DISCONNECTED! Reason code ({reason_code.value}) {reason_code.getName()}!")
63-
64-
mqtt_client.on_connect = on_connect_cb
65-
mqtt_client.on_disconnect = on_disconnect_cb
66-
67-
mqtt_topic_root = os.environ["mqtt_topic_root"]
68-
69-
# connect to MQTT Cloud on port 8883 (default for MQTT)
70-
mqtt_client.connect(os.environ["mqtt_server"], int(mqtt_port))
71-
72-
# Hook up to termination signal (for docker image) and CTRL-C
73-
print("Listening to streams. Press CTRL-C to exit.")
74-
75-
sdf = app.dataframe(input_topic)
76-
77-
def publish_to_mqtt(data, key, timestamp, headers):
78-
json_data = json.dumps(data)
79-
message_key_string = key.decode('utf-8') # Convert to string using utf-8 encoding
80-
# publish to MQTT
81-
mqtt_client.publish(mqtt_topic_root + "/" + message_key_string, payload = json_data, qos = 1)
82-
83-
sdf = sdf.apply(publish_to_mqtt, metadata=True)
84-
85-
86-
# start the background process to handle MQTT messages
87-
mqtt_client.loop_start()
88-
89-
print("Starting application")
90-
# run the data processing pipeline
91-
app.run(sdf)
92-
93-
# stop handling MQTT messages
94-
mqtt_client.loop_stop()
95-
print("Exiting")
27+
if __name__ == '__main__':
28+
app.run()

0 commit comments

Comments
 (0)