#Local MQTT communication
1 messages ยท Page 1 of 1 (latest)
I'm creating this thread to keep information about your problem in a easier to access location by the way
Thanks , will use this going forward
Awesome! That'll make it easier for me to keep track of the adjustments. Since I've been looking at using mqtt at some point I was interested
Additionally, I would use one of the nightly builds, not the beta, just because right now the nightly is pretty stable
I just loaded the board with nightly build and initiated the code.py . Its executing fine as of now , Will have to wait a few minutes to see if I 'm hitting the connection error . Will keep you posted
so after few minutes I got the communication error but it auto connected again which is good . The auto connect did not happen in 6.3
O2: 1786 ppm
Temperature: 26.4 *C
Humidity: 51.3 %
Publishing to airquality/co2
Traceback (most recent call last):
File "code.py", line 121, in <module>
File "adafruit_minimqtt/adafruit_minimqtt.py", line 754, in reconnect
File "adafruit_minimqtt/adafruit_minimqtt.py", line 441, in connect
File "adafruit_minimqtt/adafruit_minimqtt.py", line 266, in _get_connect_socket
File "adafruit_esp32spi/adafruit_esp32spi_socket.py", line 75, in connect
File "adafruit_esp32spi/adafruit_esp32spi.py", line 761, in socket_connect
File "adafruit_esp32spi/adafruit_esp32spi.py", line 663, in socket_open
File "adafruit_esp32spi/adafruit_esp32spi.py", line 325, in _send_command_get_response
File "adafruit_esp32spi/adafruit_esp32spi.py", line 295, in _wait_response_cmd
File "adafruit_esp32spi/adafruit_esp32spi.py", line 277, in _check_data
RuntimeError: Expected 01 but got 00
Code done running.
Adafruit CircuitPython 7.0.0-rc.0-6-g4922e67b8 on 2021-09-02; Adafruit Matrix Portal M4 with samd51j19
soft reboot
Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.
code.py output:
Connecting to WiFi...
Connected!
Attempting to connect to 192.168.11.123
Connected to MQTT Broker!
hmmm. I'm not fond of the soft reboot, but if it solves your problem that's good.
Personally I'd rather 'try again', can you post your code around line 121?
And it failed again with the error. This time it did not auto start
Traceback (most recent call last):
File "code.py", line 121, in <module>
File "adafruit_minimqtt/adafruit_minimqtt.py", line 754, in reconnect
File "adafruit_minimqtt/adafruit_minimqtt.py", line 441, in connect
File "adafruit_minimqtt/adafruit_minimqtt.py", line 266, in _get_connect_socket
File "adafruit_esp32spi/adafruit_esp32spi_socket.py", line 75, in connect
File "adafruit_esp32spi/adafruit_esp32spi.py", line 761, in socket_connect
File "adafruit_esp32spi/adafruit_esp32spi.py", line 663, in socket_open
File "adafruit_esp32spi/adafruit_esp32spi.py", line 325, in _send_command_get_response
File "adafruit_esp32spi/adafruit_esp32spi.py", line 295, in _wait_response_cmd
File "adafruit_esp32spi/adafruit_esp32spi.py", line 277, in _check_data
RuntimeError: Expected 01 but got 00
Sure will do
Line 121-- mqtt_client.reconnect()
could you post like ten lines above and below that?
Get Values from sensor
i2c = board.I2C()
scd4x = adafruit_scd4x.SCD4X(i2c)
print("Serial number:", [hex(i) for i in scd4x.serial_number])
scd4x.start_periodic_measurement()
print("Waiting for first measurement....")
while True:
try:
if scd4x.data_ready:
print("CO2: %d ppm" % scd4x.CO2)
print("Temperature: %0.1f *C" % scd4x.temperature)
print("Humidity: %0.1f %%" % scd4x.relative_humidity)
print("Publishing to %s" % mqtt_topic)
mqtt_client.publish(mqtt_topic, "%d" % scd4x.CO2)
print()
time.sleep(60)
except RuntimeError:
wifi.reset()
mqtt_client.reconnect()
121 is the last line
ok, let's try some changes. Give me a moment first, I want to read through one of the comments another user made in the main help channel just to make sure I know what I'm doing
Sure np
hmm. I'm not sure what they're suggesting. We'll just have to wait for their help when they're able. Until then we can try the changes I'm more familiar with. If I'm lucky, their solution will work for me too, though my workaround does work.
Ok first of a couple of questions
is it safe to assume that when the wifi goes down, or when the power goes out, the device having a problem reconnecting is 'ok' (we can work on it later, I'm just making sure I can prioritize it correctly) or does the wifi go out often enough that that would be an issue?
The wifi is pretty stable , I have ubiquiti AP's . So never had that scenario of wifi going out and the board reconnecting
awesome, it's really not that big of an issue, just needed to make sure I understood the problem
After a few minutes of running the code, it throws the error mentioned above and I had to phhysically pull out the plug and plug it in to make it work
ok, you're still connected to the serial output so you can read print statements right?
yup I am
except RuntimeError:
reconnect_limit = 10
reconnect_tries = 0
print("Connection Dropped, trying to reconnect")
while reconnect_tries < reconnect_limit:
try:
wifi.reset()
mqtt_client.reconnect()
except RuntimeError:
reconnect_tries += 1
print(reconnect_tries, " Failures")
put this code in place of your runtime error
sure
it should be indented so it works, but basically we're safely 'trying to reconnect'. If I had to bet, I think this won't solve our problem, but it should help us understand what is going on
oh wait, I need to make it break, give me a moment
roger that
except RuntimeError as e:
reconnect_limit = 10
reconnect_tries = 0
print("Connection Dropped, trying to reconnect")
while reconnect_tries < reconnect_limit:
try:
wifi.reset()
mqtt_client.reconnect()
except RuntimeError:
reconnect_tries += 1
print(reconnect_tries, " Failures")
if reconnect_tries >= reconnect_limit:
raise(e)```
there we go, that way if it fails to ever reconnect in those 10 tries, it will hard break
But, if it ever prints print(reconnect_tries, " Failures"), then stops counting up, and starts printing print("CO2: %d ppm" % scd4x.CO2), then we know this approach reconnected us
Updated the code and its running , it might take like 15-20 ish minutes until we hit the error
I will keep you posted
thanks for the explanation !
No worries, that's a great reason to use the thread option on discord, makes it easier to run something and 'wait' for a failure
no problem, my code sets up the wifi connect information in a class, that way I can move all of that messy 'reconnect' information elsewhere in my program. I'm mostly basing this approach off of that. I think the problem is actually with sockets and opening more than we close, but we'll slowly work our way there so we can be confident about what exactly the problem was
Awesome,sounds good. So far so good..no errors
And it stopped
Connection Dropped, trying to reconnect
1 Failures
2 Failures
3 Failures
4 Failures
5 Failures
6 Failures
7 Failures
8 Failures
9 Failures
10 Failures
Traceback (most recent call last):
File "code.py", line 131, in <module>
File "code.py", line 116, in <module>
File "adafruit_minimqtt/adafruit_minimqtt.py", line 621, in publish
File "adafruit_esp32spi/adafruit_esp32spi_socket.py", line 86, in send
File "adafruit_esp32spi/adafruit_esp32spi.py", line 721, in socket_write
RuntimeError: Failed to send 16 bytes (sent 0)
Code done running.
brb in 10 min
ok, did it ever successfully reconnect?
ok, so at no point did it start saying, 1, 2, 3 failures, then CO2: 1786 ppm, Temperature: 26.4 *C, Humidity: 51.3 %
Right , there were no reconnection after failure
Ok cool, it's a bummer, but it's to be expected. Now lets look at how you initialize all of your connections
Can you show me all of the code used to setup mqtt_client and wifi?
Will do ,stepping away for 10 min
no worries, I have a few other projects I'll be able to take care of in the mean time ๐
WiFi
try:
from secrets import secrets
except ImportError:
print("WiFi secrets are kept in secrets.py, please add them there!")
raise
If you are using a board with pre-defined ESP32 Pins:
esp32_cs = DigitalInOut(board.ESP_CS)
esp32_ready = DigitalInOut(board.ESP_BUSY)
esp32_reset = DigitalInOut(board.ESP_RESET)
spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)
"""Use below for Most Boards"""
status_light = neopixel.NeoPixel(
board.NEOPIXEL, 1, brightness=0.2
)
wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light)
Connect to WiFi
print("Connecting to WiFi...")
wifi.connect()
print("Connected!")
Topic Setup
MQTT Topic
Use this topic if you'd like to connect to a standard MQTT broker
mqtt_topic = "airquality/co2"
Code
Define callback methods which are called when events occur
pylint: disable=unused-argument, redefined-outer-name
def connect(mqtt_client, userdata, flags, rc):
# This function will be called when the mqtt_client is connected
# successfully to the broker.
print("Connected to MQTT Broker!")
print("Flags: {0}\n RC: {1}".format(flags, rc))
def disconnect(mqtt_client, userdata, rc):
# This method is called when the mqtt_client disconnects
# from the broker.
print("Disconnected from MQTT Broker!")
def subscribe(mqtt_client, userdata, topic, granted_qos):
# This method is called when the mqtt_client subscribes to a new feed.
print("Subscribed to {0} with QOS level {1}".format(topic, granted_qos))
def unsubscribe(mqtt_client, userdata, topic, pid):
# This method is called when the mqtt_client unsubscribes from a feed.
print("Unsubscribed from {0} with PID {1}".format(topic, pid))
def publish(mqtt_client, userdata, topic, pid):
# This method is called when the mqtt_client publishes data to a feed.
print("Published to {0} with PID {1}".format(topic, pid))
def message(client, topic, message):
# Method callled when a client's subscribed feed has a new value.
print("New message on topic {0}: {1}".format(topic, message))
socket.set_interface(esp)
MQTT.set_socket(socket, esp)
Set up a MiniMQTT Client
mqtt_client = MQTT.MQTT(broker = secrets['broker'],
username = secrets['user'],
password = secrets['pass'],
port = 1883)
Connect callback handlers to mqtt_client
mqtt_client.on_connect = connect
mqtt_client.on_disconnect = disconnect
mqtt_client.on_subscribe = subscribe
mqtt_client.on_unsubscribe = unsubscribe
mqtt_client.on_publish = publish
mqtt_client.on_message = message
print("Attempting to connect to %s" % mqtt_client.broker)
mqtt_client.connect()
print("Subscribing to %s" % mqtt_topic)
mqtt_client.subscribe(mqtt_topic)
can you link me to the learn guide this came from?
It came from multiple guides
sweet thank you
I've got to go grab lunch and get some things done, I'll jump back here once I've read through everything and have an idea of what to suggest next
Sure , thank you !
Still doing updates, but
instead of trying, mqtt_client.reconnect()
Because you reset the wifi, could you give a shot at,
while reconnect_tries < reconnect_limit:
try:
try:
mqtt_client.disconnect()
except RuntimeError as e:
print("encountered error while trying to close mqtt connection,\n", e)
wifi.reset()
mqtt_client.connect()
except RuntimeError:
reconnect_tries += 1
print(reconnect_tries, " Failures")
I'm loosely wondering if we should instead be trying to close and connect again rather than reconnect if the wifi was reset
if that doesn't work we'll try,
except RuntimeError as e:
reconnect_limit = 10
reconnect_tries = 0
print("Connection Dropped, trying to reconnect")
while reconnect_tries < reconnect_limit:
try:
mqtt_client.reconnect()
except RuntimeError:
reconnect_tries += 1
print(reconnect_tries, " Failures")
if reconnect_tries >= reconnect_limit:
raise(e)
which just tries to reconnect multiple times without the wifi reset
indent those three lines one more level in/to the right
That should be the except pair to the try right below the while
It needs one more space, and the lines below it need to be indented in as well
Sorry I am new to python
This one is one me, I went one level too far in because I saw it was off by a space
It needs to come back out one level to the left,--my bad
while reconnect_tries < reconnect_limit:
try:
try:
mqtt_client.disconnect()
except RuntimeError as e:
print("encountered error while trying to close mqtt connection,\n", e)
wifi.reset()
mqtt_client.connect()
except RuntimeError:
reconnect_tries += 1
print(reconnect_tries, " Failures")
does line 119 looks ok ?
So that's a warning, not an error
Different code editors can treat it like an error. Sometimes you want that behavior, because if you've written a lot of code, and you have lots of variable that are made but never used, it very easy to accidentally use it and you end up with a weird error that's really hard to follow. This helps prevent you from having that happen
Earlier we printed that e, or raised it.. in fact there might be a block of code below this one you're missing where we raise that e
oh okay good to know. The MU editor is a powerful editing tool with lots of information
It really is, I'm not that great when it comes to understanding editors personally, but they are powerful
let me know if you ever see it print(reconnect_tries, " Failures") or print("encountered error while trying to close mqtt connection,\n", e)
I should have made it make note of hitting that runtime error, but we'll deal with it later, for now let's just run it and see what happens
I wish we weren't bodging it with 'try again' stuff, but networking is messy, and a microcontroller only has so much ability to deal with network packets being dropped. "try again" usually works on my end
Yeah I know, networking is all over the place. so many devices on 2.4 ghz wifi network .. I hope the try again works
CO2: 2131 ppm
Temperature: 26.1 *C
Humidity: 53.1 %
Publishing to airquality/co2
Connection Dropped, trying to reconnect
Disconnected from MQTT Broker!
1 Failures
Traceback (most recent call last):
File "code.py", line 126, in <module>
File "adafruit_minimqtt/adafruit_minimqtt.py", line 519, in disconnect
File "adafruit_minimqtt/adafruit_minimqtt.py", line 955, in is_connected
MMQTTException: MiniMQTT is not connected.
Code done running.
It just stopped an neopixel is white
Ok cool, that's really informative if I'm reading it correctly
So, what happened was we tried to disconnect, and mqtt said, "I'm already disconnected" which is a good thing
oh okay
try:
mqtt_client.disconnect()
except RuntimeError, MMQTTException as e:
print("encountered error while trying to close mqtt connection,\n", e)
#wifi.reset()
Let's try this, we're now catching that exception that way if we try to disconnect, we know we've already been disconnected
I'm also commenting out the wifi reset for the moment--I want to hold off on that
ok its running now
I can do the full code if you like
no thats fine
awesome!
Just asking
Connected to MQTT Broker!
Flags: 0
RC: 0
Disconnected from MQTT Broker!
Connected to MQTT Broker!
Flags: 0
RC: 0
Disconnected from MQTT Broker!
Connected to MQTT Broker!
Flags: 0
RC: 0
Disconnected from MQTT Broker!
Connected to MQTT Broker!
Flags: 0
RC: 0
unfortunately I coudn't get the lines above it
It ran fine for few minutes and printed above
I am going to do bbq now for the weekend , I will catch up with you on this later . I appreciate the help
Thanks !
Could you paste your full source code here? https://paste.pythondiscord.com/
Ah no worries, you have a good one. This thread will archive, but you can open it back up when you get back. I'm slowly trying to get a feel for what's going on code wise and at least it feels like we're making progress
Awesome, sounds good . You have a good rest of the day
you too and have a great weekend
Ok jumping back over here--Auto101, @heady dew has been working on their own mqtt implementation and has similar issues so I've invited them to this thread as well
(I'd ping you but I'm going to guess it's late in the day)
So, give me a minute to clean up my code, but I'll post a sample of my 'json' sensor relay data
Yep. Trying to put one baby to sleep and give the other one a bath.
I'm updating the code as a whole, so I can add and remove sensors without the program crashing on startup, and I'm trying to make every sensor fit into a similar class which is tripping me up--perfect is the enemy of good in this case--and once that update is running, I'm going to build a mqtt clone so we can address the mqtt protocol and since you're both running into this same issue, we'll be able to make guides be a bit clearer, and I'll be more ready to help users with this kind of question.
Tldr, I'll post the code shortly
And the code is bad--I'm awful at networking, I have a bunch of glue code that exists because it was there once the program worked, not because it's ever used
This is one of the situations when I prefer Raspberry Pi + blinka over CircuitPython.
I've not yet looked super deep into MQTT, but I feel like mqtt's constantly on setup plus networking fun shenanigans is the problem here, I'm willing to bet it's more a fault of the router than the micro in the long run, but getting the micro ready to handle the networking randomness is important regardless. I think that 'being able to handle the randomness' is very solvable though
Just my personal bias: microcontrollers shouldn't be doing TCP/IP. So many things can go wrong. You need a full networking stack for sufficient robustness.
That's a fair bias, but from what I've done I'd disagree. There's a lot to be gained with the 2.5ghz bandwidth and having a micro on it is great. Some protocols might be poorly adapted for a micro, but micro's on the spectrum are amazing from my (albeit brief) experience
I specifically meant TCP/IP.
There are simpler protocols like packet radio, BLE advertisements and CAN that are much more suited to microcontrollers.
The happy path scenarios in TCP/IP are easy to implement on microcontrollers. The rainy day scenarios need a full TCP/IP stack and those don't fit on microcontrollers.
Thanks @barren zodiac for re opening this thread. I am available to troubleshoot any code that you may advise
Awesome!
I'm still cleaning up my sensor code, I'm hoping to get it done shortly
Ok, the code is a mess, but it's functionally stable. Now that I finally have that, I can start trying to make an mqtt fork of this so we can explore how it works
The extra bells and whistles are .. eh, and the 'everything' around the code.py file itself is mostly out of date. I wasn't sure what I had commited vs what I hadn't, so it's there now I suppose
Took more than a minute to get it in this sorry state, but so it goes, it's easier to fix code that exists, than fix nearly perfect code that doesn't exist.
Do you want me to make any changes in my code referencing above ?
I'm not sure yet.
Ok
I have my sensors reporting now, and now that I have that 'json-post' program is working, I'm going to try the mqtt setup. But the 'try again' setup is how I'm managing networking issues
The code does a whole lot of different failure preperation, and those
try:
response = self.https.post(post_sensor_webpage, json=packet_json)
success = True
pixels[0]=(0,0,0)
pixels.show()
try:
self._close_request_socket(response)
except Exception as e:
print("During closing of socket, error occured", e)
except RuntimeError as e:
# Reasons
# Server may be down
run_count += 1
print("> Runtime Error Caught", e)
success = False
except OSError as e:
self.connected_to_network = False
print("> Os Error Caught", e)
success = False
except OutOfRetries as e:
print(">Outofretries>", e)
success = False
try/excepts, are really useful--but there's still a lot of straggling code I need to remove. For example the run_count is now a invalid variable because I adjusted the function to return with a failed success flag, whereas before it sat trying again over and over
try:
self._close_request_socket(response)
except Exception as e:
print("During closing of socket, error occured", e)
except RuntimeError as e:
# Reasons
# Server may be down
run_count += 1
print("> Runtime Error Caught", e)
success = False```
this block is where the program manages errors most often, and it's going to be the basis of how I try and manage mqtt errors--on a failure I'm going to try to close the socket, then open a new one up, and try again
Awesome, thanks for the explanation
@heady dew This is the sensor logging code I use in my home setup (with recent updates for cp7rc1
Awesome! I will take a look at it.
I ended up with other transient issues, and it could be because I have so many sensors connected by QWIIC cables forming a large antenna.
Hopefully the QWIIC featherwing can alleviate some of those issues.
hmm. How many sensors and what's the total length of the cable (roughly)
8 sensors
this part is embarrassing
1.5 feet
๐
I need shorter QWIIC cables
may be more like 2.5 feet
๐ฉ
The real fun starts when I put an OLED display at the end of the chain and the display falls apart.
ah yeah that probably approaches the signal degradation length. Have you looked at dropping the clock speed
oof, you need multiple micros managing and handing off communications at that level
yep
Ok, well I'm going to walk away from the computer for a while for a fresh point of view, and between this evening and tomorrow I should hopefully have a pi running an mqtt receiver, and a esp32-s2 sending it data. Then I can start testing how to handle the broken transmissions
(Gotta keep this thread on topic otherwise close it and move to general ๐ )
Scientists are actually preoccupied with accomplishment. So they are focused on whether they can do something. They never stop to ask if they should do something.
Jurassic World
I can't know if I should use mqtt in this case until I know how it fails. Plus you two aren't the only ones who've asked about it, and I want remote sensor logging, so it's a good motivation for me to thoroughly explore it. In the absence of mqtt, the json communication works pretty well if you have a server ready for posted strings
Last thing I am going to say about cable length. Adafruit or Sparkfun has an I2C signal conditioner for exactly this kind of situation.
Huh. This is probably going to be something I'll need soon-I've got a 3 accelerator setup where they'll be spread over about 1.5m apiece. Good to know. But that's for the future, mqtt is what we're solving now ๐
baby steps before feature creep sets in
I went with ESP32-S2 with MQTT because that's what I had on hand.
I also thought of BLE advertisements or CAN bus.
Those two will probably save me from WiFi interference in the QWIIC cables, but not with cable length.
I think you're running into two different kinds of errors there though. One for i2c bus noise, and one for mqtt transmission drop recovery. If you have a server that can take a posted json file, you can swap from mqtt to the json without issue (my example code linked above show's how it handles failed sends) but you'll still have the read errors from the i2c bus due to it's length.
But I might be misreading your comment and that's something you know and have handled--my brain is grinding to a halt and it's getting harder to focus hence the walk away
You are right. My setup has two issues. I am more interested in solving the intermittent WiFi/MQTT connectivity issue. The I2C bus issue can be handled with other strategies.
In the very short term you can take a look through the json strategy, you have to make sure the total size of the json packets is fairly small otherwise it gets an error. In the mean time I'm going to setup the mqtt version, and give that a shot.
Found it: https://www.adafruit.com/product/4756
Did you ever end up trying communicating with adafruits server per the learn guide?
No , I wanted to keep it local
Yup running MQTT as a add on in HA
Ok, I'm going to do something different and run it on a local flask server, so if that causes an issue in debugging I'll do the HA, but I am less familiar with that personally.
Oh okay , just for the information I have few devices that communicate via Mqtt such as lights , motion sensors ,rf bridge and they work perfectly fine