6435067-spec/tuya-local-esp32
GitHub: 6435067-spec/tuya-local-esp32
两个单头文件的 ESP32 编解码器,支持在局域网内直接控制 Tuya 协议 3.4/3.5 设备,无需云端。
Stars: 0 | Forks: 0
# Tuya Local for ESP32 — 协议 3.4 与 3.5
**English** · [Русский](README.ru.md) · [עברית](README.he.md) · [Español](README.es.md)
两个独立的单头文件 codec,可直接与 Tuya Wi-Fi 设备通信——例如继电器、
插座、电能表——**直接在你的 LAN 上进行,无需 cloud**。只需提供一个 IP、
一个 16 字节的 local key 和一个 datapoint,即可通过 TCP 读取状态或切换继电器。
* **[Tuya34.h](Tuya34.h)** — 协议 **3.4**:`0x55AA` 帧,AES-ECB payload + HMAC-SHA256。
* **[Tuya35.h](Tuya35.h)** — 协议 **3.5**:`0x6699` 帧,AES-GCM (IV + tag)。
相同的握手,相同的 API —— 你只需切换头文件和类型,其他都不用改。仅依赖于
ESP32 Arduino core (`WiFi` + 内置 mbedtls) 和 ArduinoJson v7。
## 为什么会有这个项目
公开的 ESP32 Tuya **3.5** LAN 协议实现非常稀少 —— 大多数
库仅停留在 3.3/3.4。此处的 3.4 codec 已经在一个锅炉房运行了多年,
驱动着三个泵/加热器继电器;而 3.5 codec 是通过逆向 [tinytuya](https://github.com/jasonacox/tinytuya) 的帧结构开发的,并且已在真实
硬件上验证(ESP32-D0WD-V3 对接 Tuya 3.5 加热器继电器):握手、状态读取
(`0x10` 和 `0x0A`) 以及控制功能均正常工作。
这两个头文件是从生产环境的固件中提取出来的,并且是与设备无关、
与项目无关的代码块 —— 设备以 struct 的形式传入,没有任何硬编码内容。
## 用法
```
#include "Tuya35.h" // or "Tuya34.h" for a 3.4 device
Tuya35Device dev = {
"192.168.1.50",
{ '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' }, // local key, 16 bytes
"1", // relay DP (often "1"; sockets sometimes "switch_1")
6668 // local Tuya port
};
Tuya35 tuya(dev);
bool on; float watts; String raw;
tuya.read(0x10, &on, &watts, &raw); // read status (0x10 = DP_QUERY_NEW, 0x0A = fallback)
tuya.setRelay(true, &watts, &raw); // switch on, then read back power if the device meters it
```
对于 3.4 设备,用法完全相同,只是去掉了查询命令参数:
`tuya.read(&on, &watts, &raw)`。
设置 `Tuya35::DBG = true;`(或 `Tuya34::DBG`)可以在
Serial 中输出每一帧的完整十六进制转储 —— 它能帮你区分“非 0x6699 帧”错误和“GCM auth FAIL”
(key 错误),这是调试 Tuya 连接时最常见的操作。
## 获取 local key
该 key 由 Tuya cloud 按设备发放一次:
1. 在 Tuya / Smart Life app 中配对设备。
2. 将该 app 关联到一个 [Tuya IoT](https://iot.tuya.com/) cloud 项目。
3. 运行 [`tinytuya wizard`](https://github.com/jasonacox/tinytuya)(或 `tuya-cli`) ——
它会打印出每个设备的 16 字符 local key 和 datapoint 映射。
在你的路由器中将设备的 DHCP 地址固定下来,以免其 IP 发生变动。
**切勿将真实的 key 提交到公开的代码库中。**
## 示例
| Sketch | 说明 |
|---|---|
| [RelayControl](examples/RelayControl/RelayControl.ino) | 最简示例:包含一个头文件,读取状态,切换继电器。通过一个 `#define` 即可在 3.4 和 3.5 之间切换。 |
| [Tuya35_TestBench](examples/Tuya35_TestBench/Tuya35_TestBench.ino) | 3.5 codec 的独立交互式调试台:提供 Serial 菜单,可针对单个设备执行握手 / 读取 / 开 / 关操作,并带有十六进制日志记录。 |
两者均可在 `arduino-cli` 中针对 `esp32:esp32:esp32` 顺利通过编译检查。
## 协议工作原理 (3.5)
```
frame: PREFIX(0x00006699) | 00 00 | seq(4) | cmd(4) | len(4) | IV(12) | ciphertext | TAG(16) | SUFFIX(0x00009966)
```
* Payload 为 AES-GCM;**AAD 为前缀之后的 14 个头部字节**
(`unknown + seq + cmd + len`),tag 用于对它们进行身份验证。
* 握手 `NEG_START → NEG_RESP → NEG_FINISH`:设备返回一个 remote nonce
以及 `HMAC(local_key, local_nonce)`;session key 为
`AES-GCM(local_key, iv = nonce[:12], data = local_nonce ⊕ remote_nonce)` ——
仅取 ciphertext,丢弃 tag。
* `CONTROL_NEW` 在 JSON 之前需要一个 15 字节的版本头 `"3.5" + 12×00`。
3.4 的结构相同,但使用 `0x55AA` 组帧和 AES-ECB + HMAC 来代替 GCM;
握手和命令代码是共享的。组帧参考:
[tinytuya](https://github.com/jasonacox/tinytuya) (`core/header.py`,
`message_helper.py`, `XenonDevice.py`)。
## 安装
将 `Tuya34.h` / `Tuya35.h` 放在你的 sketch 旁边,或者将此代码库克隆到你的
Arduino `libraries/` 文件夹中(它自带了 `library.properties`,因此示例会显示在
File → Examples 下)。从 Library Manager 安装 ArduinoJson (v7)。
## 许可证
MIT — 查看 [LICENSE](LICENSE)。
标签:C++, ESP32, 嵌入式开发, 数据擦除, 智能家居, 涂鸦协议, 物联网