ESP8266运行MicroPython接收MQTT消息触发OSError -1求助
ESP8266 MicroPython MQTT 接收消息触发 OSError -1 解决方案
问题背景
搭载1MiB最新MicroPython固件的ESP8266,配合带LED控制按钮的Java Vaadin Web应用,按钮用于发布MQTT指令控制LED开关。ESP端程序可正常连接WiFi和MQTT Broker,但Vaadin发布消息时,ESP触发无额外参数的OSError -1。
环境信息
- MQTT Broker:本地Docker部署的HiveMQ
- 烧录工具:Thonny
- ESP8266已成功连接WiFi
现有代码
MicroPython 代码
import machine from umqtt.simple import MQTTClient import network import time ssid = "ssid" password = "password" wlan = network.WLAN(network.STA_IF) wlan.active(True) wlan.connect(ssid, password) while not wlan.isconnected(): pass print("hallo") MQTT_TOPIC = "led/control" LEDstatus = "off" ClientID = "Alabama" LED_PIN = machine.Pin(2, machine.Pin.OUT) LED_PIN.value(1) def mqtt_callback(topic, msg): if msg.decode() == "on": LEDstatus = "on" LED_PIN.value(0) elif msg.decode() == "off": LEDstatus = "off" LED_PIN.value(1) client = MQTTClient(b"Alabama", b"192.168.2.125", 1883) client.set_callback(mqtt_callback) client.connect() client.subscribe(MQTT_TOPIC) while True: try: client.check_msg() time.sleep(10) except OSError as e: print("Fehler beim Empfangen der Nachricht:") print(e.args) client.disconnect() break
Java Vaadin 发布代码
public void publishToDashboard(String topic, String message, String clientID) throws ExecutionException, InterruptedException, JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); Map<String, String> payload = new HashMap<>(); payload.put("clientID", clientID); payload.put("message", message); String strPayload = objectMapper.writeValueAsString(payload); Mqtt5Publish mqttMessage = Mqtt5Publish.builder() .topic(topic) .payload(strPayload.getBytes()) .contentType("json") .qos(MqttQos.AT_LEAST_ONCE) .build(); this.client.publish(mqttMessage).get(); System.out.println("published"); }
private void publishLED(ClickEvent<Button> event, String msg, String clientID) { CompletableFuture.runAsync(() -> { try { client.publishToDashboard("led/control", msg, clientID); } catch (ExecutionException | InterruptedException | JsonProcessingException ex) { throw new RuntimeException(ex); } }); }
问题分析
- Payload格式不匹配:Vaadin端发送的是包含
clientID和message字段的JSON格式Payload,但ESP端回调函数直接将消息解码为纯字符串"on"/"off",解析失败触发OSError -1。 - 变量作用域问题:ESP回调函数中修改
LEDstatus时未声明global,会创建局部变量,虽然不直接触发错误,但会导致状态变量无法正确更新。 - MQTT版本兼容性(潜在):Vaadin使用MQTT5客户端发布消息,而
umqtt.simple默认使用MQTT 3.1.1,部分MQTT5特性可能引发解析异常。
解决方案
1. 修正ESP端Payload解析逻辑
导入MicroPython内置的ujson库,解析JSON格式的Payload,提取message字段进行判断,同时修复变量作用域问题:
import machine from umqtt.simple import MQTTClient import network import time import ujson # 新增JSON解析库 ssid = "ssid" password = "password" wlan = network.WLAN(network.STA_IF) wlan.active(True) wlan.connect(ssid, password) while not wlan.isconnected(): pass print("hallo") MQTT_TOPIC = "led/control" LEDstatus = "off" ClientID = "Alabama" LED_PIN = machine.Pin(2, machine.Pin.OUT) LED_PIN.value(1) def mqtt_callback(topic, msg): global LEDstatus # 声明使用全局变量 try: # 解析JSON格式的Payload payload = ujson.loads(msg.decode()) message = payload.get("message", "") if message == "on": LEDstatus = "on" LED_PIN.value(0) elif message == "off": LEDstatus = "off" LED_PIN.value(1) except Exception as e: print("Payload解析错误:", e) client = MQTTClient(b"Alabama", b"192.168.2.125", 1883) client.set_callback(mqtt_callback) client.connect() client.subscribe(MQTT_TOPIC) while True: try: client.check_msg() time.sleep(10) except OSError as e: print("Fehler beim Empfangen der Nachricht:") print(e.args) # 尝试重新连接,避免单次错误导致程序终止 time.sleep(5) client.connect() client.subscribe(MQTT_TOPIC)
2. 统一MQTT版本(可选)
在Vaadin端创建MQTT客户端时指定使用MQTT 3.1.1协议,避免版本兼容问题:
Mqtt5Client client = Mqtt5Client.builder() .identifier("vaadin-client") .serverHost("192.168.2.125") .serverPort(1883) .protocolVersion(MqttVersion.MQTT_3_1_1) // 指定MQTT 3.1.1版本 .build();
验证步骤
- 重新烧录修改后的MicroPython代码到ESP8266
- 启动Vaadin应用和HiveMQ Broker
- 点击按钮发布指令,检查ESP是否正常接收消息并控制LED,同时查看串口输出是否有错误信息
内容的提问来源于stack exchange,提问作者Larshle
相关产品推荐
相关产品推荐

