← index #363Issue #85
Related · high · value 1.642
QUERY · ISSUE

umqtt.simple's check_msg triggers OSError -1 with TLS servers

openby SylvainGarriguesopened 2019-12-23updated 2024-08-25

Please consider this code:

import utime
from umqtt.simple import MQTTClient

mqtt = MQTTClient("test_mqtt_client_id", "test.mosquitto.org",
                  port=8883, keepalive=30, ssl=True)

def on_topic_updated(topic, msg):
    print((topic, msg))

mqtt.set_callback(on_topic_updated)
mqtt.connect()
mqtt.subscribe(b"Topic/For/Sylvain")
while True:
    print("Checking msg...")
    mqtt.check_msg()
    utime.sleep(1)

It systematically gives the same output (and I can reproduce it with another broker e.g. AWS IoT)

$ /usr/local/Cellar/micropython/1.11/bin/micropython  main.py
Checking msg...
Checking msg...
Traceback (most recent call last):
  File "main.py", line 15, in <module>
  File "/Users/sylvain/.micropython/lib/umqtt/simple.py", line 204, in check_msg
  File "/Users/sylvain/.micropython/lib/umqtt/simple.py", line 173, in wait_msg
OSError: -1

What's strange is that if I use port 1883 and ssl=False (i.e. no encryption), the same code works.

I reproduced this issue on my Mac (MicroPython 1.11) and on my ESP8266 board (MicroPython 1.12).

Looping over mqtt.wait_msg() works like a charm, so I suspect switching back and forth a TLS socket from blocking to non-blocking generates such error.

5 comments
domenc · 2020-01-01

Same here (ESP8266 and MicroPython 1.12). When change SSL to noSSL connection, works fine.

samf48 · 2020-05-05

I too have this issue using a ublox modem and AWS over TLS. Are there any workarounds?

sactre · 2020-07-07

Same problem, in ESP32 it works perfectly but in ESP8266 it doesn't.

CharlieAt · 2021-02-07

there seems to be some kind of problem when the ssl socket is set to nonblocking and it occasionally returns b"" which results in the OSError(-1). Ignoring it did not help. to work around the problem I created a poll object after the ssl_wrap and in check_msg() I check the poll object instead of mucking around with setblocking(True/False).

YMMV / workaround / not an optimal solution, but it works for me

simple.py

def connect(self, clean_session=True):
    ...
    if self.ssl:
        import ussl
        self.sock = ussl.wrap_socket(self.sock, server_hostname=self.server)
    self.p = uselect.poll()
    self.p.register(self.sock, uselect.POLLIN)    

def check_msg(self):
    #self.sock.settimeout(0.0) #setblocking(False)
     res = self.p.ipoll(0)
     for s,e in res:
        if e & uselect.POLLIN: 
            return self.wait_msg()
     return None   

and comment out the #self.sock.setblocking(True) in get_msg()

GadiHerman · 2024-08-25

According to my test, the problem does not occur because of SSL. The problem is because the server's waiting time is over according to the keepalive=??? My solution is to add a timer that PINGs the server before the keepalive time expires. This solves the problem. Here is a sample code to solve the problem:

from machine import Pin, Timer
from umqtt.simple import MQTTClient
import ujson
import sys
import os

LED = Pin(2, Pin.OUT)
PING_PERIOD   = 120

CHANNEL_TOKEN = 'token_XXXXX'
CHANNEL_NAME  = 'esp32'
RESOURCE_NAME = 'led'
MQTT_SERVER = 'mqtt.beebotte.com'
MQTT_USER = 'token:' + CHANNEL_TOKEN
MQTT_TOPIC = CHANNEL_NAME + '/' + RESOURCE_NAME

def handleTimerInt(timer):
    client.ping()
    print('ping')
    
def callback_func(topic, msg):
    print("topic:",topic," msg:", msg)
    json_data= ujson.loads(msg)
    dt= json_data["data"]
    print("Data:"+str(dt))
    if str(dt) == 'True':
        LED.value(1)
    if str(dt) == 'False':
        LED.value(0)

# create a random MQTT clientID
random_num = int.from_bytes(os.urandom(3), 'little')
mqtt_client_id = bytes('client_'+str(random_num), 'utf-8')

client = MQTTClient(mqtt_client_id, MQTT_SERVER, user=MQTT_USER, password='', keepalive=PING_PERIOD*2  )

myTimer = Timer(0)

try:      
    client.connect()
    myTimer.init(period=PING_PERIOD*1000, mode=Timer.PERIODIC, callback=handleTimerInt)
except Exception as e:
    print('could not connect to MQTT server {}{}'.format(type(e).__name__, e))
    sys.exit()
    
client.set_callback(callback_func)
client.subscribe(MQTT_TOPIC)

while True:
    try:
        client.wait_msg()
    except KeyboardInterrupt:
        print('Ctrl-C pressed...exiting')
        client.disconnect()
        sys.exit()
CANDIDATE · ISSUE

umqtt.simple: multiple subscribe() need check_msg()

closedby puuuopened 2016-08-01updated 2016-08-12

Example script:

import time
from umqtt.simple import MQTTClient

def sub_cb(topic, msg):
    print((topic, msg))

def main(server="localhost"):
    c = MQTTClient("umqtt_client", server)
    c.set_callback(sub_cb)
    c.connect()
    c.subscribe(b"foo_topic")
    #time.sleep_ms(100)
    #c.check_msg()
    c.subscribe(b"bar_topic")
    while True:
        c.wait_msg()

    c.disconnect()

Running with mosquitto MQTT broker seems to work fine with:

$ mosquitto_pub -t "foo_topic" -m "1"
$ mosquitto_pub -t "bar_topic" -m "1"
$ mosquitto_pub -t "bar_topic" -m "3"

However, having a retained message,

$ mosquitto_pub -t "foo_topic" -m "1" -r

the start of the script fails with:

Traceback (most recent call last):
  File "example_sub_multi.py", line 21, in <module>
  File "example_sub_multi.py", line 14, in main
  File "/home/frederik/Downloads/micropython-lib/umqtt.simple/umqtt/simple.py", line 104, in subscribe
AssertionError:

Having a look in the code shows that subscribe() is expecting the
answer of the second subscribe (0x90), but since the message of the
first subscribe arrived, the AssertionError is thrown. So,
uncommenting sleep_ms() and check_msg() results in a working
script.

@pfalcon: This is a bug or by intention?

2 comments
pfalcon · 2016-08-07

This is definitely a bug, feel free to propose a patch.

puuu · 2016-08-12

Solved with #89

Keyboard

j / / n
next pair
k / / p
previous pair
1 / / h
show query pane
2 / / l
show candidate pane
c
copy suggested comment
r
toggle reasoning
g i
go to index
?
show this help
esc
close overlays

press ? or esc to close

copied