[MQTT] Using micropython lib: usocket.getaddrinfo

Hi there,
I’m trying to use MQTT from an OpenMV camera. I’m using the umqtt.simple library [1].

I’m getting an error trying to connect the client to the broker.

The culprit seems to be usocket’s geaddrinfo. In a simplified script, the following code also barfs:

usocket.getaddrinfo("10.11.16.12", 1883)

Any pointers in how to go about it?



[1]micropython-lib/simple.py at master · micropython/micropython-lib · GitHub

The actual code for the test:


import sensor, image, time, network, sys
import usocket as socket

# Reset sensor
sensor.reset()

# Set sensor settings
sensor.set_contrast(1)
sensor.set_brightness(1)
sensor.set_saturation(1)
sensor.set_gainceiling(16)
sensor.set_framesize(sensor.QQVGA)
sensor.set_pixformat(sensor.GRAYSCALE)

SSID='xxxxx'     # Network SSID
KEY='xxxxx'      # Network key
HOST = ''   # Use first available interface
PORT = 8000 # Arbitrary non-privileged port

# Init wlan module and connect to network
print("Trying to connect... (may take a while)...")

wlan = network.WINC()
wlan.connect(SSID, key=KEY, security=wlan.WPA_PSK)

# We should have a valid IP now via DHCP
print(wlan.ifconfig())

print("check 10.11.16.12")
print(socket.getaddrinfo("10.11.16.12", 1883))

clock = time.clock()

while(True):
    clock.tick()
    img = sensor.snapshot()
    img.draw_string(0, 0, "FPS:%.2f"%(clock.fps()), color = (0xFF, 0x00, 0x00))

Hi, getaddrinfo() resolves a hostname to an ip using the DNS server, for example:

addr = usocket.getaddrinfo("www.google.com", 80)[0][4]
# Create a new socket and connect to addr
s = usocket.socket(usocket.AF_INET, usocket.SOCK_STREAM)
s.connect(addr)

Sometimes it doesn’t work and throws an exception (OSError -2 == No Entry) I’ll look into that, for now you should call it more than once:

for i in range(10):
    try:
        addr = usocket.getaddrinfo("www.google.com", 80)[0][4]
        break
    except:
        pass

That said, you don’t need to call it if you have the ip, you could just connect using the ip+port tuple:

s.connect(("10.11.16.12", 1883))

Thank you for the reply. I guess what would make sense is for getaddrinfo to check if you are providing an IP, then do not try to resolve.

Regardless, what I found out, the current modusocket.c implementation for stm32 does provide write or read commands, which are needed used by the underlying Python libraries I’ve found. I tried to replace write with send and read with recv which seem to be pretty close. However it does not seem to work.

Looking for alternatives. One option would be to use HTTP to send data instead of MQTT. Any directions on how to POST to an address from OpenMV?

No, but it should be just like normal Python code, there’s also a GET example in the WiFi shield examples. If you tell me how to test the MQTT library I can help debug it (server name? what happens, what should happen etc…)

You can test using the public mosquitto broker, the url is test.mosquitto.org. You would connect to it over port 1883

client = MQTTClient("camera1", "test.mosquitto.org", port=1883)
client.connect()
client.publish("openmv/test", "Hello World!")

If you have the mosquitto client installed in your machine you can register a subscriber:

mosquitto_sub -h test.mosquitto.org -t "openmv/test" -v

You should see Hello World! in your console when you run the OpenMV python code.

Hi, please try the attached script.
simple.py (6.37 KB)

Yes! that seems to work. It failed for me initially when I was testing against a local broker, then I tested against the test.mosquitto.org and a broker hosted in EC2 and it worked.

Just in case it is helpful for someone else, what follows is the traceback:

Traceback (most recent call last):
  File "<stdin>", line 48, in <module>
  File "mqtt.py", line 63, in connect
TypeError: object 'NoneType' is not a tuple or list

Hi, I’m happy to report that getaddrinfo is now fixed (it was just a timeout). The fix will be available in the next release as well as an MQTT example.