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

设备成功订阅并响应:

相关推荐
小蜗牛的路6 小时前
docker MySQL容器导入sql文件
sql·mysql·docker
互联网哪些事情6 小时前
Docker 部署项目到云服务器完整步骤
docker·服务器部署docker·云主机部署docker
Amy_au7 小时前
Building a Containerised Backend with Docker Compose
运维·docker·容器
java_logo7 小时前
Docker 部署银河麒麟高级服务器操作系统(Kylin Linux)生产级全流程
服务器·docker·kylin·银河麒麟部署·银河麒麟部署文档·银河麒麟linux·银河麒麟linux部署教程
Lxinccode8 小时前
ESP32-S3(2) : 安装ESP-IDF
esp32·esp32s3·esp-idf安装
Lxinccode9 小时前
ESP32(1) : 安装开发环境Arduino IDE
单片机·嵌入式硬件·esp32·arduinoide
岳来9 小时前
docker 容器HostConfig 字段 示例
docker·hostconfig
喵叔哟10 小时前
16.项目架构设计
后端·docker·容器·.net
眠りたいです11 小时前
Docker核心技术和实现原理第一部分-Docker镜像制作
运维·docker·容器·集群·镜像·dockerfile
面对疾风叭!哈撒给11 小时前
Liunx之Docker 安装启动 influxdb2
java·spring cloud·docker