# mijia-api Go 重构设计(2026-07-16) > [!NOTE] > This document may not reflect the current implementation. > See the final report for up-to-date state: > [Final Report](../reports/mijia-go-api.md) ## [S1] 问题 将 Python 版 mijia-api(v4.1.2)重构为纯 Go 库,只保留 API 核心功能,排除 skills、MCP server、CLI、decrypt 调试脚本、文档站。 ## [S2] 方案概览 - 项目形态:纯 Go 库,module 路径 `git.misaka.ren/m1saka/mijia-go-api`,包名 `mijia`,代码放仓库根目录。 - 功能范围:完整底层 API + 高级设备封装(mijiaDevice 等价物)。 - Go 版本:1.22+,尽量只用标准库;二维码终端输出用 `github.com/mdp/qrterminal/v3`。 ## [S3] 包结构 ``` / (package mijia) crypto.go ← miutils.py: GenNonce / SignedNonce / RC4-drop1024 加解密 / 签名 / GenerateEncParams(有序 KV) auth.go ← 登录: QRLogin、passToken 静默刷新、auth.json 读写、UA/deviceId 生成 client.go ← Client 结构、session headers/cookies、统一加密请求 request() api.go ← GetHomesList / GetDevicesList(分页) / GetSharedDevicesList / GetScenesList / RunScene / GetConsumableItems / GetDevicesProp / SetDevicesProp / RunAction / GetStatistics / CheckNewMsg device.go ← Device 高级封装: miot-spec 抓取解析+缓存、Get/Set(类型与 range 校验)/RunAction errors.go ← ERROR_CODE 表 + 错误类型(LoginError/APIError/DeviceGetError/DeviceSetError 等) types.go ← 请求/响应结构体 ``` ## [S4] 认证与加密关键点 1. 二维码扫码登录:`account.xiaomi.com/pass/serviceLogin` → `longPolling/loginUrl` → 终端二维码 → 长轮询(120s)→ 回调取 serviceToken;响应需去 `&&&START&&&` 前缀。 2. passToken 有效时静默刷新 token;auth.json 保存 ua/deviceId/pass_o/ssecurity/serviceToken/passToken/userId/cUserId/expireTime(30 天)等。 3. 加密请求(base `https://api.mijia.tech/app`,全部 POST form): - nonce = base64(8 字节随机 + 分钟时间戳字节);signedNonce = base64(SHA256(ssecurity||nonce))。 - RC4 必须先丢弃 1024 字节 keystream(标准库 crypto/rc4 手动 drop)。 - 双重签名:先对明文 params 签 `rc4_hash__`,RC4 加密后再签 `signature`;签名串顺序固定 `POST&uri&data=..&rc4_hash__=..&signedNonce`,Go 用有序 KV 切片而非 map。 - data JSON 必须紧凑无空格。 - 响应可能是 gzip 压缩后的 RC4 密文:先直接 JSON 解析,失败则解密,解密后 UTF-8 无效再 gzip 解压。 4. `Available()`:检查 auth 字段完备 + 调 check_new_msg 验证,结果缓存 60 秒。 ## [S5] API 方法映射 与 Python 版一一对应(URI、请求体 JSON 完全一致),注意: - GetDevicesList 分页(start_did/max_did,直到 has_more=false),home_id 为空时遍历所有家庭。 - RunAction 逐条请求,prop get/set 批量。 - 多数接口需 home 的 owner uid(从 GetHomesList 查)。 - SetDevicesProp code==1 表示网关已接收但结果未知;非 0/1 查 ERROR_CODE 附中文消息。 ## [S6] 高级设备封装 `NewDevice(api, did 或 name)`: - 从设备列表解析 model → GET `https://home.miot-spec.com/spec/{model}` 正则提取内嵌 JSON → 解析 services/properties/actions(siid/piid/aiid、类型、rw、range、value-list)→ 本地 JSON 缓存(auth.json 同目录)。 - `Get(name)` / `Set(name, value)`(bool/int/float 类型转换、range 与枚举校验)/ `RunAction(name, args...)`;属性名 `-` 与 `_` 互为别名。不做 Python 的动态属性语法糖。 ## [S7] 错误处理与测试 - 错误:哨兵/自定义错误类型 + ERROR_CODE map(码→中文)。 - 测试:crypto.go 的纯函数(nonce 格式、signedNonce、RC4-drop1024、签名串)用与 Python 实现对照生成的固定向量做单测;spec HTML 解析用本地样本。网络调用不做集成测试。 ## [S8] 排除项 mcp_server.py、skills/、docs/、decrypt/、`__main__.py` CLI、qrcode 图片生成(仅终端二维码)。