← index #363Issue #754
Related · high · value 2.319
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 got OSError: -1 after publishing 65535 packets message on esp32

openby mzhboyopened 2023-10-21updated 2023-10-21

platform: MicroPython v1.21.0 on 2023-10-06; Generic ESP32 module
broker: mosquitto
description:
got OSError: -1 after sending 65535 packets

Result:

pkcnt 65000
Traceback (most recent call last):
File "<stdin>", line 47, in <module>
File "<stdin>", line 40, in publish_test
File "umqtt/simple.py", line 144, in publish
File "umqtt/simple.py", line 184, in wait_msg
OSError: -1

code:

from umqtt.simple import MQTTClient
import time
import ujson as json
from machine import unique_id
import sys, os

def str_current_time():
    tm_ns = time.time_ns()
    tm_rem_ms = (tm_ns % 1_000_000_000) // 1_000_000
    tm = time.localtime(tm_ns//1_000_000_000)
    str_tm = str(tm[3])+':'+str(tm[4])+':'+str(tm[5])+'.'+ str(tm_rem_ms)
    return str_tm
   

id = unique_id() #machine.unique_id()
id_str = '{:02x}{:02x}{:02x}{:02x}'.format(id[0], id[1], id[2], id[3])

mq_id = id_str
mq_machine = os.uname().machine.split()[0]
mq_server = '192.168.12.25'
mq_user='esp32-srv'
mq_pass='123456'
mq_topic= b'esp/test'
mq_message = {'id':mq_id, 'machine': mq_machine, 'time': str_current_time(), 'hello': 'hello'}
mqClient = MQTTClient(mq_id, mq_server, port=1883, user=mq_user, password=mq_pass, keepalive=60*60*12)
mqClient.connect(clean_session=True) # only support clean_sesson=True
mqClient.publish(b'esp/hello', json.dumps(mq_message), qos=1)

pkcnt = 0x00_00_00_01
pkcnt_max = 999_999

def publish_test():
    global pkcnt, pkcnt_max
    pkcnt += 1
    if pkcnt >= pkcnt_max :
        pkcnt = 1
    tm = time.time()
    message = {'id':mq_id, 'machine': mq_machine, 'time': tm, 'current': 1, 'ctrl': 1, 'pkcnt':pkcnt}
    mq_message = json.dumps(message)
    mqClient.publish(mq_topic, mq_message, qos=1)
    if pkcnt % 1000 == 0:
        print('pkcnt',pkcnt, 'time', tm)

if __name__ == '__main__' :
    print('test start')
    while True :
        publish_test()
2 comments
mzhboy · 2023-10-21

also tried reconnect after exception, didn't work

    try :
        mqClient.publish(mq_topic, mq_message, qos=1)
    except OSError as err:
        print('error: when publish,', err)
        try :
            mqClient.connect()
        except Exception as err2 :
            print('error: when reconnect,', err2)            
    
mzhboy · 2023-10-21

how ever mqtt_as has no issue

"pkcnt": 147481,

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