使用 Docker 搭建 EMQX,并通过 MicroPython 实现 MQTT 控制 ESP32 LED

使用 Docker 搭建 EMQX,并通过 MicroPython 实现 MQTT 控制 ESP32 LED

在物联网项目中,MQTT 是最常用的消息通信协议之一。本文将通过一个完整示例,演示如何:

  1. 使用 Docker 快速部署 EMQX
  2. 解决端口冲突问题
  3. 使用 MicroPython 作为 MQTT 客户端
  4. 通过 MQTT 消息 远程控制 ESP32 LED

一、使用 Docker 快速启动 EMQX

1. 基础启动命令

最基础的 EMQX 容器启动方式如下:

bash 复制代码
docker run -itd \
  --name emqx \
  -p 1883:1883 \
  -p 8083:8083 \
  -p 8084:8084 \
  -p 8883:8883 \
  -p 18083:18083 \
  emqx/emqx

容器启动成功后会返回类似 ID:

text 复制代码
185326ea778710a12c77ad3b3e24800ce7591c30f4feb0196742bfd70f655d14

这样:

  • 宿主机:1884
  • 容器内部:1883(MQTT 默认端口)

二、访问 EMQX 控制台

浏览器访问(HTTPS):

复制代码
https://服务器IP:18083

默认账号密码:

text 复制代码
用户名:admin
密码:public

控制台界面如下:


三、MicroPython MQTT 客户端实现

ESP32 使用 MicroPython ,MQTT 客户端代码基于 simple.py 实现。


1. MQTT 客户端库(simple.py

文件名:simple.py

python 复制代码
import usocket as socket
import ustruct as struct
from ubinascii import hexlify


class MQTTException(Exception):
    pass


class MQTTClient:
    def __init__(
        self,
        client_id,
        server,
        port=0,
        user=None,
        password=None,
        keepalive=0,
        ssl=None,
    ):
        if port == 0:
            port = 8883 if ssl else 1883
        self.client_id = client_id
        self.sock = None
        self.server = server
        self.port = port
        self.ssl = ssl
        self.pid = 0
        self.cb = None
        self.user = user
        self.pswd = password
        self.keepalive = keepalive
        self.lw_topic = None
        self.lw_msg = None
        self.lw_qos = 0
        self.lw_retain = False

    def _send_str(self, s):
        self.sock.write(struct.pack("!H", len(s)))
        self.sock.write(s)

    def _recv_len(self):
        n = 0
        sh = 0
        while 1:
            b = self.sock.read(1)[0]
            n |= (b & 0x7F) << sh
            if not b & 0x80:
                return n
            sh += 7

    def set_callback(self, f):
        self.cb = f

    def set_last_will(self, topic, msg, retain=False, qos=0):
        self.lw_topic = topic
        self.lw_msg = msg
        self.lw_qos = qos
        self.lw_retain = retain

    def connect(self, clean_session=True):
        self.sock = socket.socket()
        addr = socket.getaddrinfo(self.server, self.port)[0][-1]
        self.sock.connect(addr)
        premsg = bytearray(b"\x10\0\0\0\0\0")
        msg = bytearray(b"\x04MQTT\x04\x02\0\0")

        sz = 10 + 2 + len(self.client_id)
        msg[6] = clean_session << 1
        if self.user:
            sz += 2 + len(self.user) + 2 + len(self.pswd)
            msg[6] |= 0xC0

        i = 1
        while sz > 0x7F:
            premsg[i] = (sz & 0x7F) | 0x80
            sz >>= 7
            i += 1
        premsg[i] = sz

        self.sock.write(premsg, i + 2)
        self.sock.write(msg)
        self._send_str(self.client_id)
        if self.user:
            self._send_str(self.user)
            self._send_str(self.pswd)

        resp = self.sock.read(4)
        if resp[3] != 0:
            raise MQTTException(resp[3])

    def subscribe(self, topic, qos=0):
        self.cb is not None
        pkt = bytearray(b"\x82\0\0\0")
        self.pid += 1
        struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid)
        self.sock.write(pkt)
        self._send_str(topic)
        self.sock.write(qos.to_bytes(1, "little"))

    def check_msg(self):
        self.sock.setblocking(False)
        try:
            res = self.sock.read(1)
        except:
            return
        if res == b"\x30":
            self.sock.read(1)
            tlen = self.sock.read(2)
            tlen = (tlen[0] << 8) | tlen[1]
            topic = self.sock.read(tlen)
            msg = self.sock.read()
            self.cb(topic, msg)

四、ESP32 主程序(控制 LED)

文件名:main.py

python 复制代码
from simple import MQTTClient
from machine import Pin
import network

led = Pin(2, Pin.OUT)

SSID = "wifi名称"
PASSWORD = "wifi密码"

wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
    wlan.connect(SSID, PASSWORD)
    while not wlan.isconnected():
        pass

print("Network config:", wlan.ifconfig())

SERVER = "192.168.31.219"
PORT = 1884
CLIENT_ID = "my_micropython_client"

def sub(topic, msg):
    print(topic, msg)
    if topic == b"led002":
        if msg == b"on":
            led.value(0)
        elif msg == b"off":
            led.value(1)

client = MQTTClient(
    CLIENT_ID,
    SERVER,
    PORT,
    "test",
    "123456"
)

client.set_callback(sub)
client.connect()
client.subscribe(b"led002")

while True:
    client.check_msg()

五、测试效果

通过 EMQX 控制台或其他 MQTT 客户端:

  • Topic:led002

  • Payload:

    • on → LED 亮
    • off → LED 灭

设备成功订阅并响应:

相关推荐
engchina8 小时前
WSL Ubuntu で Kubernetes v1.34.2 + Docker 環境を構築する
ubuntu·docker·kubernetes
oMcLin12 小时前
2025年必备的Docker命令指南与实战示例
docker·容器·eureka
AtoposのCX33012 小时前
Docker运行hello-world镜像失败或超时
运维·docker
sun cat12 小时前
Docker详细介绍(6)
docker·容器·docker-compose
小Pawn爷16 小时前
4.镜像仓库
docker
江湖有缘18 小时前
零基础入门:使用 Docker 快速部署 Organizr 个人主页
java·服务器·docker
礼拜天没时间.20 小时前
深入Docker架构——C/S模式解析
linux·docker·容器·架构·centos
猫头虎20 小时前
如何使用Docker部署OpenClaw汉化中文版?
运维·人工智能·docker·容器·langchain·开源·aigc
会周易的程序员20 小时前
openplc runtimev4 Docker 部署
运维·c++·物联网·docker·容器·软件工程·iot
小Pawn爷20 小时前
1.Docker基础
运维·docker·容器