You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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);
            }
        });
    }

问题分析

  1. Payload格式不匹配:Vaadin端发送的是包含clientID和message字段的JSON格式Payload,但ESP端回调函数直接将消息解码为纯字符串"on"/"off",解析失败触发OSError -1。
  2. 变量作用域问题:ESP回调函数中修改LEDstatus时未声明global,会创建局部变量,虽然不直接触发错误,但会导致状态变量无法正确更新。
  3. 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();

验证步骤

  1. 重新烧录修改后的MicroPython代码到ESP8266
  2. 启动Vaadin应用和HiveMQ Broker
  3. 点击按钮发布指令,检查ESP是否正常接收消息并控制LED,同时查看串口输出是否有错误信息

内容的提问来源于stack exchange,提问作者Larshle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 18:44:52