使用 Docker 搭建 EMQX,并通过 MicroPython 实现 MQTT 控制 ESP32 LED
在物联网项目中,MQTT 是最常用的消息通信协议之一。本文将通过一个完整示例,演示如何:
- 使用 Docker 快速部署 EMQX
- 解决端口冲突问题
- 使用 MicroPython 作为 MQTT 客户端
- 通过 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 灭
设备成功订阅并响应:
