使用 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 灭

设备成功订阅并响应:

相关推荐
何以不说话1 小时前
记录一下学习日常⑩(docker)
linux·运维·docker·容器
Knight_AL2 小时前
Docker 部署 Milvus 并连接现有 MinIO 对象存储
docker·eureka·milvus
你的不安3 小时前
Docker相关知识
docker·容器
淬炼之火3 小时前
基于Docker Desktop 和 Ubuntu 在 Windows上部署轻量化大模型(Qwen-LLM)
笔记·ubuntu·docker·语言模型·容器
是火云哦4 小时前
打包你的开发环境:Docker 从入门到上瘾
运维·docker·容器
小明_GLC4 小时前
关于租用阿里云服务器拉取Docker镜像的问题
docker
今晚打佬虎4 小时前
精准阻断 Docker 容器映射端口:流量路径诊断与 iptables 配置
运维·docker·容器
那年一路北4 小时前
基于 Maven + Docker 的 WebApp 打包与部署
docker·maven·web app
阡陌..5 小时前
Linux下用docker调用pytorch-无法检测到cuda问题
linux·pytorch·docker
KubeSphere 云原生5 小时前
在 KubeSphere 上运行 Moltbot(Clawdbot):自托管 AI 助手的云原生实践
docker·云原生·容器