mqttmicropythonraspberry-pi-picoraspberry-pico-w

MQTTClient throws error when trying to connect


I'm devopling an application on a PicoW using Visual Studio (Thonny gives the same results).

It uses umqtt.simple:

from machine import Pin, I2C
from time import sleep
import network
from umqtt.simple import MQTTClient
import config

# MQTT Parameters
MQTT_SERVER = config.mqtt_server
MQTT_PORT = 0
MQTT_USER = config.mqtt_username
MQTT_PASSWORD = config.mqtt_password
MQTT_CLIENT_ID = b"rPi_pico_train_1"
MQTT_KEEPALIVE = 7200
MQTT_SSL = True

led = Pin("LED", Pin.OUT)

def flash_led(count):
    _count = count
    while _count > 0:
        led.value(True)
        sleep(0.25)
        led.value(False)
        sleep(0.05)
        _count -= 1

def init_wifi(ssid, password):
    led.value(0)
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    wlan.connect(ssid, password)
    
    connection_timeout = 20
    print("Waiting for WIFI Connection...")
    while connection_timeout > 0:
        if wlan.status() >= 3:
            break
        connection_timeout -= 1
        print(f"Timeout in: {connection_timeout}")
        sleep(1)
    if wlan.status() != 3:
        return False
    else:
        print("Connected!")
        network_info = wlan.ifconfig()
        print(f"IP: {network_info[0]}")
        led.value(1)
    return True

def sub_cb(topic, msg):
    print("New message on topic {}".format(topic.decode('utf-8')))
    msg = msg.decode('utf-8')
    print(msg)

if init_wifi(config.wifi_ssid, config.wifi_password):
    flash_led(2)
else:
    print("NOT CONNECTED TO WIFI")

client = MQTTClient(MQTT_CLIENT_ID, MQTT_SERVER,0, MQTT_USER, MQTT_PASSWORD, 3600,{'server_hostname' : MQTT_SERVER})
client.connect()
client.set_callback(sub_cb)
print('Connected to %s MQTT Broker'%(client))
print("Connecting to client")
flash_led(5)
print("Client listening")
while True:
    client.subscribe('trains')
    sleep(1)

Here's my server details: enter image description here

Presumbly, my client iVar isn't init'd correcly, but having looked at Hive and Tom's Hardware, I've run to a stop.

EDIT

Thanks for @Brits comment about not inclusing client.connect(). I've re-written and started afresh a couple of times and must have missed that!

Unfortunately I still can't connect. The error is now:

Waiting for WIFI Connection...
Connected!
IP: 192.168.1.183
Traceback (most recent call last):
  File "<stdin>", line 69, in <module>
  File "/lib/umqtt/simple.py", line 68, in connect
AttributeError: 'dict' object has no attribute 'wrap_socket'

The line quoted in the module - line 69 - is the line of my code that contains: client.connect().

How is my code not connecting properly to Hive?


Solution

  • client = MQTTClient(MQTT_CLIENT_ID, MQTT_SERVER,0, MQTT_USER, MQTT_PASSWORD, 3600,{'server_hostname' : MQTT_SERVER})
    client.set_callback(sub_cb)
    print('Connected to %s MQTT Broker'%(client))
    

    You are not calling client.connect i.e.

    client = MQTTClient(MQTT_CLIENT_ID, MQTT_SERVER,0, MQTT_USER, MQTT_PASSWORD, 3600,{'server_hostname' : MQTT_SERVER})
    client.set_callback(sub_cb)
    client.connect()
    print('Connected to %s MQTT Broker'%(client))
    

    client.connect sets self.sock which subscribe uses (self.sock.write(pkt) - line 157 in simple.py); hence the error.

    Update

    Ref your subsequent error File "/lib/umqtt/simple.py", line 68, in connect, that line (and the line before) is:

    if self.ssl:
                self.sock = self.ssl.wrap_socket(self.sock, server_hostname=self.server)
    

    So self.ssl is set. This will be because you call

    client = MQTTClient(MQTT_CLIENT_ID, MQTT_SERVER,0, MQTT_USER, MQTT_PASSWORD, 3600,{'server_hostname' : MQTT_SERVER})
    

    where:

    def __init__(
            self,
            client_id,
            server,
            port=0,
            user=None,
            password=None,
            keepalive=0,
            ssl=None,
        ):
    

    so you are setting ssl to {'server_hostname' : MQTT_SERVER}. Unfortunately, based on this discussion and the source, it looks like this parameter changed in version 1.4 and you need something like the following (copied from the discussion):

    context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
    context.verify_mode = ssl.CERT_NONE
    client = MQTTClient(client_id=b"kudzai_raspberrypi_picow", server=b"8fbadaf843514ef286a2ae29e80b15a0.s1.eu.hivemq.cloud", port=0, user=b"mydemoclient", password=b"passowrd", keepalive=7200, ssl=context )
    

    Note: Sorry I don't actually use this currently, so cannot provide a fully working example I can just tyy to point out where you probably need to look (and looking at the library source is a good starting point with issues like this, unfortunately to keep the size down and performance up the library does not validate parameters).