esp32c3刷卡miIO控制米家智能插座

项目地址:ESP32-C3-Mijia-Card-Power-Switch: 米家刷卡取电开关esp32c3代码


1. 项目背景
1.1 为什么做这个项目
为了方便战队对公用设备的使用进行管理,决定制作实名刷卡使用焊台的项目,选用米家智能插座本身可以通过手机 App 控制,但在固定工作台场景里,App的功能太少,并且无法记录使用,更适合用“刷卡”这种实体交互方式。
本项目使用 ESP32-C3 作为主控,通过 RC522 读取 RFID 卡片,再用局域网 miIO UDP 协议控制米家智能插座,实现刷卡开关电源。
1.2 要解决的问题
这个项目主要解决三个问题:
- 本地快速控制
不通过手机 App、不依赖云端,ESP32-C3 直接向插座发送 miIO UDP 控制命令。 - 简单授权判断
通过卡片 UID 做本地白名单判断,只有配置过的 UID 才能控制插座。 - 操作记录可追溯
每次刷卡都会保存记录,包括 UID、是否授权、控制结果和时间信息。记录写入 ESP32-C3 的 NVS,断电重启后不会丢失。
1.3 技术选型
项目基于 ESP-IDF 开发,不使用 Arduino 工程。
主要技术组成:
- ESP32-C3:负责 Wi-Fi、任务调度、Web 服务和 miIO 控制。
- RC522:通过 SPI 与 ESP32-C3 通信,读取 13.56 MHz 卡片。
- OLED:通过 I2C 显示运行状态。
- miIO 协议:通过 UDP 54321 端口与米家智能插座通信。
- NVS:保存刷卡记录,防止断电丢失。
- HTTP Server:提供网页和 JSON API 查看刷卡记录。
2. 项目介绍
2.1 硬件和通信接口
硬件主要由三部分组成:
- ESP32-C3 主控
- 连接 2.4 GHz Wi-Fi。
- 运行 ESP-IDF 程序。
- 负责 miIO 加密通信、刷卡记录保存和 Web 服务。
- RC522 读卡模块
- 使用 SPI 通信。
- 默认引脚包括 MISO、MOSI、SCLK、CS、RST。
- 读取卡片 UID,并尝试读取卡片姓名。
- OLED 显示屏
- 使用 I2C 通信。
- 显示启动、Wi-Fi、刷卡、授权和插座状态。
2.2 软件模块设计
项目采用模块化结构:
- Wi-Fi 模块
- 负责连接路由器。
- 获取 ESP32-C3 的局域网 IP。
- 判断当前 Wi-Fi 是否可用。
- RFID 模块
- 初始化 RC522。
- 监听卡片进入和移除事件。
- 读取 UID,并将 UID 转成紧凑的大写十六进制字符串。
- 控制模块
- 判断 UID 是否在授权白名单内。
- 对同一张卡做消抖处理,避免短时间重复触发。
- 授权后调用 miIO 模块控制插座。
- miIO 模块
- 通过 UDP 与插座通信。
- 使用 token 派生 AES key 和 IV。
- 对请求 JSON 进行 AES-CBC 加密。
- 对响应数据进行 MD5 校验和 AES 解密。
- 优先使用 set_properties,失败时回退到 set_power。
- 刷卡记录模块
- 保存 UID、姓名、授权状态、控制结果、时间。
- 使用环形缓冲保存最近 100 条记录。
- 使用 NVS 槽位式写入,每次只写当前记录,减少 NVS 占用和写入失败风险。
- Web 模块
- 提供网页查看最近刷卡记录。
- 提供 /api/records JSON 接口。
- 页面每 5 秒自动刷新。
2.3 运行流程
系统启动后,主要流程如下:
ESP32-C3 启动
-> 初始化 NVS
-> 初始化 OLED
-> 初始化刷卡记录
-> 连接 Wi-Fi
-> 启动 SNTP 时间同步
-> 启动 Web 服务
-> 初始化 miIO 客户端
-> 初始化 RC522
-> 等待刷卡
刷卡后的流程:
检测到卡片
-> 读取 UID
-> 读取卡片姓名
-> 发送刷卡事件到 controller
-> 判断 UID 是否授权
-> 如果未授权,记录 denied
-> 如果授权,查询插座当前状态
-> 计算目标状态
-> 发送 miIO 控制命令
-> 保存刷卡记录
-> OLED 显示结果
2.4 数据保存机制
刷卡记录保存在 ESP32-C3 的 NVS 中。
每条记录包含:
- sequence:记录序号。
- uid:卡片 UID。
- holder_name:卡片姓名。
- authorized:是否授权。
- result:控制结果,例如 plug_on、plug_off、denied。
- epoch_time:校时后的时间。
- uptime_ms:设备启动后的毫秒数。
当前最多保存最近 100 条记录。超过 100 条后,新记录会覆盖最旧记录。
为了避免一次性写入过大的 NVS blob,项目采用槽位式保存方式:每次刷卡只写当前记录槽位和元数据,而不是把全部 100 条记录整包写入。
2.5 miIO 控制细节
你要得到你接入你账号米家的设备ip和token来实现miIO协议控制。
IP 很好获取:进路由器后台,看 DHCP/已连接设备列表,按设备名 焊台 或 MAC 14:D8:81:72:CD:20 找到对应 IP。你之前贴出来的 IP: 192.168.1.113 就是这个值。建议在路由器里给这个 MAC 做“静态 DHCP/地址保留”,避免 IP 变化。
token 获取推荐用 python-miio:
pip install python-miio micloud miiocli cloud
按提示输入小米账号、密码、地区。国内米家一般选 cn。输出里会列出设备:
Name: 焊台 Model: cuco.plug.v3 IP: 192.168.1.113 Token: 32位十六进制字符串
拿到后填到项目的 main/private_config.h:
#define APP_PLUG_IP "192.168.1.113" #define APP_PLUG_TOKEN_HEX "这里填32位token"
也可以先试本地发现:
miiocli discover
它能发现同一局域网内的 miIO 设备,有时会显示 token;如果 token 是 ???、全 0 或全 f,就不能用,需要走云端获取。
验证 token 是否正确:
miiocli device --ip 192.168.1.113 --token 你的32位token info
能返回设备型号/固件信息,说明 IP 和 token 是对的。
参考:
- python-miio 获取 token / 发现设备文档:https://python-miio.readthedocs.io/en/latest/discovery.html
- Home Assistant Xiaomi miIO token 获取说明:https://www.home-assistant.io/integrations/xiaomi_miio/#retrieving-the-access-token
米家智能插座使用 miIO 本地协议通信,核心流程如下:
- ESP32-C3 向插座发送 hello 包。
- 插座返回设备 ID 和时间戳。
- ESP32-C3 使用 token 派生 AES key 和 IV。
- 控制命令被封装成 JSON。
- JSON 经过 AES-CBC 加密后发送。
- 插座返回加密响应。
- ESP32-C3 校验 MD5,并解密响应。
- 如果 set_properties 失败,则尝试 set_power 回退命令。
token 必须是 32 个十六进制字符,并且必须对应当前插座绑定状态。
2.6 Web 查看记录

ESP32-C3 启动 HTTP 服务后,可以通过浏览器访问设备 IP:
http://<esp32-ip>/
页面会显示最近刷卡记录,包括时间、UID、授权状态、控制结果和卡片姓名。
也可以访问 JSON API:
http://<esp32-ip>/api/records
如果 SNTP 没同步成功,网页会尝试用浏览器时间给 ESP32-C3 设置时间,避免刷卡记录一直只有 uptime。










