-
Notifications
You must be signed in to change notification settings - Fork 51
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Create minimqtt_multipub_simpletest.py #191
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
# SPDX-FileCopyrightText: 2023 DJDevon3 | ||
# SPDX-License-Identifier: MIT | ||
# MQTT Multi-Feed Publish Example | ||
# Coded for Circuit Python 8.2.x | ||
|
||
import traceback | ||
import os | ||
import time | ||
import ssl | ||
import wifi | ||
import socketpool | ||
import adafruit_minimqtt.adafruit_minimqtt as MQTT | ||
from adafruit_minimqtt.adafruit_minimqtt import MMQTTException | ||
|
||
# Initialize Web Sockets (This should always be near the top of a script!) | ||
# There can be only one pool | ||
pool = socketpool.SocketPool(wifi.radio) | ||
|
||
# Add settings.toml to your filesystem | ||
# CIRCUITPY_WIFI_SSID and CIRCUITPY_WIFI_PASSWORD keys | ||
# with your WiFi credentials. Add your Adafruit IO username and key as well. | ||
# DO NOT share that file or commit it into Git or other source control. | ||
ssid = os.getenv("CIRCUITPY_WIFI_SSID") | ||
appw = os.getenv("CIRCUITPY_WIFI_PASSWORD") | ||
aio_username = os.getenv("aio_username") | ||
aio_key = os.getenv("aio_key") | ||
|
||
# MQTT Topic | ||
# Use this format for a standard MQTT broker | ||
feed_01 = aio_username + "/feeds/BME280-RealTemp" | ||
feed_02 = aio_username + "/feeds/BME280-Pressure" | ||
feed_03 = aio_username + "/feeds/BME280-Humidity" | ||
feed_04 = aio_username + "/feeds/BME280-Altitude" | ||
|
||
# Time in seconds between updates (polling) | ||
# 600 = 10 mins, 900 = 15 mins, 1800 = 30 mins, 3600 = 1 hour | ||
sleep_time = 900 | ||
|
||
|
||
# Converts seconds to minutes/hours/days | ||
# Attribution: Written by DJDevon3 & refined by Elpekenin | ||
def time_calc(input_time): | ||
if input_time < 60: | ||
return f"{input_time:.0f} seconds" | ||
if input_time < 3600: | ||
return f"{input_time / 60:.0f} minutes" | ||
if input_time < 86400: | ||
return f"{input_time / 60 / 60:.0f} hours" | ||
return f"{input_time / 60 / 60 / 24:.1f} days" | ||
|
||
|
||
# Define callback methods which are called when events occur | ||
# pylint: disable=unused-argument, redefined-outer-name | ||
def connect(client, userdata, flags, rc): | ||
# Method when mqtt_client connected to the broker. | ||
print("| | ✅ Connected to MQTT Broker!") | ||
|
||
|
||
def disconnect(client, userdata, rc): | ||
# Method when the mqtt_client disconnects from broker. | ||
print("| | ✂️ Disconnected from MQTT Broker") | ||
|
||
|
||
def publish(client, userdata, topic, pid): | ||
# Method when the mqtt_client publishes data to a feed. | ||
print("| | | Published to {0} with PID {1}".format(topic, pid)) | ||
|
||
|
||
# Initialize a new MQTT Client object | ||
mqtt_client = MQTT.MQTT( | ||
broker="io.adafruit.com", | ||
port=8883, | ||
username=aio_username, | ||
password=aio_key, | ||
socket_pool=pool, | ||
ssl_context=ssl.create_default_context(), | ||
is_ssl=True, | ||
) | ||
|
||
# Connect callback handlers to mqtt_client | ||
mqtt_client.on_connect = connect | ||
mqtt_client.on_disconnect = disconnect | ||
mqtt_client.on_publish = publish | ||
|
||
while True: | ||
# These are fake values, replace with sensor variables. | ||
BME280_temperature = 80 | ||
BME280_pressure = round(1014.89, 1) | ||
BME280_humidity = round(49.57, 1) | ||
BME280_altitude = round(100.543, 2) | ||
print("===============================") | ||
|
||
# Board Uptime | ||
print("Board Uptime: ", time_calc(time.monotonic())) | ||
print("| Connecting to WiFi...") | ||
|
||
while not wifi.radio.ipv4_address: | ||
try: | ||
wifi.radio.connect(ssid, appw) | ||
except ConnectionError as e: | ||
print("Connection Error:", e) | ||
print("Retrying in 10 seconds") | ||
time.sleep(10) | ||
print("| ✅ WiFi!") | ||
|
||
while wifi.radio.ipv4_address: | ||
try: | ||
# Connect to MQTT Broker | ||
mqtt_client.connect() | ||
mqtt_client.publish(feed_01, BME280_temperature) | ||
# slight delay required between publishes! | ||
# otherwise only the 1st publish will succeed | ||
Comment on lines
+111
to
+112
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's curious. Do you have any idea why ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, I'm unsure why that happens. I only found the workaround by giving it a delay. Was quite puzzled about that myself. I have 2 values that are being graphed together. By giving it a short delay it will publish the first two within a small enough time frame to be registered together by AdafruitIO dashboard. The other 3 data points I'm not concerned if they all publish together. This is so when I view it in the dashboard the first two points are grouped together. |
||
time.sleep(0.001) | ||
mqtt_client.publish(feed_02, BME280_pressure) | ||
time.sleep(1) | ||
mqtt_client.publish(feed_03, BME280_humidity) | ||
time.sleep(1) | ||
mqtt_client.publish(feed_04, BME280_altitude) | ||
time.sleep(1) | ||
except MMQTTException as e: | ||
print("| | ❌ MMQTTException", e) | ||
traceback.print_exception(e, e, e.__traceback__) | ||
break | ||
|
||
mqtt_client.disconnect() | ||
print("| ✂️ Disconnected from Wifi") | ||
print("Next Update: ", time_calc(sleep_time)) | ||
|
||
time.sleep(sleep_time) | ||
break |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is going to connect (and later) disconnect from the broker repeatedly. This is most likely undesired - single TCP connection is better in terms of resource utilization. The right approach is to connect first and then enter a cycle with
loop()
inside.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I figured that was the right approach as AdafruitIO /overview seems to like that approach.
Also in this screenshot if the delay isn't provided then only the first publish is recorded. I'll assume AdafruitIO wants them somewhat spaced apart with delays. They typically all show up registered as within the same minute.
I know loop is preferred for checking messages but since I'm not checking messages and this is only as a publish example I figured loop was unnecessary?
Also in my example it only connects/disconnects every 15 minutes. There's more than can go wrong by staying connected permanently in that time frame with wifi going down and other errors that I figured connect/disconnect would be a better way to go.
Will look into adding loop. Hopefully that will get all data points to publish at the same identical time too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Calling
loop()
is necessary to avoid being disconnected from the server once the keep alive timer expires.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a bit confusing as that's not how the simpletest example works. Connect, publish, disconnect works fine even without increasing the keep alive timer manually in mqtt_client setup. loop is mainly for checking for messages which I'm not at all interested in if all I want to do is connect & publish. If that's not how it should be done then the simpletest example needs to be corrected to reflect that and the RTD for MQTT.loop() needs to be updated with that bit of information.
If I remove the explicit disconnect from the bottom of the script then the next time I publish it will automatically disconnect & reconnect anyway. For subscribing keeping that connection alive would be very important but since I'm only publishing I can close it immediately.
I believe it's best practice while only publishing to disconnect explicitly because I've run into an issue where keeping that connection open while using it with multiple other API's can end up running out of sockets. Disconnecting closes the socket to be reused by another API immediately afterwards in the script.
In my main script it functions exactly as intended. This example is just a small snippet of that. I wanted to share so others don't have to pull out their hair for a week trying to figure out how to do multiple publish using pure MQTT. This is for a multi-publish simpletest so I wanted to keep it simple.