feat: 初始化小米 IoT (MIoT) 智能家居 Go 库

- 实现 MIoT 客户端核心功能(MQTT 连接、设备管理、属性读写)
- 支持云端 API 调用与局域网设备发现(mDNS)
- 集成国际化(i18n)多语言支持
- 添加 MIoT 设备规约解析器(spec_parser)
- 包含单元测试与使用示例
This commit is contained in:
2026-06-28 22:05:49 +08:00
parent ac442812b4
commit 3a44cb9e6a
118 changed files with 31630 additions and 0 deletions
+379
View File
@@ -0,0 +1,379 @@
# 第一批移植任务提示词 (P0 基础架构)
> 使用提示词时,将 `{编号}` 替换为对应任务的提示词正文。
---
## 任务 1.1 — miot_error.py → miot_error.go
```
## 任务:移植 MIoT 错误系统
源文件:D:\miot\py-miot\miot_error.py (151行)
目标文件:D:\miot\go-miot\miot_error.go (新建)
参考子文档:D:\miot\go-miot\migration\07-miot-err.md
### 需实现的内容
1. 错误码常量(Go 用 const iota,值对齐 Python 的 MIoTErrorCode 枚举):
- CODE_UNKNOWN = -10000, CODE_UNAVAILABLE = -10001, CODE_INVALID_PARAMS = -10002
- CODE_RESOURCE_ERROR = -10003, CODE_INTERNAL_ERROR = -10004
- CODE_UNAUTHORIZED_ACCESS = -10005, CODE_TIMEOUT = -10006
- CODE_OAUTH_UNAUTHORIZED = -10020, CODE_HTTP_INVALID_ACCESS_TOKEN = -10030
- CODE_MIPS_INVALID_RESULT = -10040, CODE_CERT_INVALID_CERT = -10050
- CODE_CONFIG_INVALID_INPUT = -10100, CODE_CONFIG_INVALID_STATE = -10101
- CODE_LAN_UNAVAILABLE = -10120
2. MIoTError 结构体,实现 error 接口:
- Code 字段(错误码), Message 字段(消息)
- Error() 方法返回 "code=N, message=xxx" 格式
- ToDict() 方法返回 map[string]interface{}
3. 13 个子错误类型(Go 用类型别名 + 构造函数):
MIoTOauthError, MIoTHttpError, MIoTMipsError, MIoTDeviceError,
MIoTSpecError, MIoTStorageError, MIoTCertError, MIoTClientError,
MIoTEvError, MipsServiceError, MIoTConfigError, MIoTOptionsError,
MIoTLanError
4. 文件头注释标注 "package miot"
### 注意事项
- 无外部依赖,可独立编译
- 每个子类型提供 NewXxxError(message string) 构造函数
- 错误码用 const int 定义,不要用 iota(因为值不是连续的)
```
---
## 任务 1.2 — const.py → const.go
```
## 任务:移植 MIoT 常量系统
源文件:D:\miot\py-miot\const.py (161行)
目标文件:D:\miot\go-miot\const.go (新建)
参考子文档:D:\miot\go-miot\migration\08-miot-constant.md
### 需实现的内容
1. 字符串常量:
DOMAIN="xiaomi_home", DEFAULT_NAME="Xiaomi Home", DEFAULT_NICK_NAME="Xiaomi"
OAUTH2_CLIENT_ID, OAUTH2_AUTH_URL, DEFAULT_OAUTH2_API_HOST
DEFAULT_CLOUD_BROKER_HOST, DEFAULT_CLOUD_SERVER, DEFAULT_CTRL_MODE
DEFAULT_INTEGRATION_LANGUAGE, OAUTH_REDIRECT_URL
2. 数值常量:
MIHOME_HTTP_API_TIMEOUT=30, MIHOME_MQTT_KEEPALIVE=60
MIHOME_CERT_EXPIRE_MARGIN=3600*24*3, NETWORK_REFRESH_INTERVAL=30
SPEC_STD_LIB_EFFECTIVE_TIME=3600*24*14
MANUFACTURER_EFFECTIVE_TIME=3600*24*14
3. 变量(切片/映射,需在 var() 中定义):
SUPPORTED_PLATFORMS []string — 18 个平台名
UNSUPPORTED_MODELS []string — 4 个模型
CLOUD_SERVERS map[string]string — 6 个区域
SUPPORT_CENTRAL_GATEWAY_CTRL []string — ["cn"]
INTEGRATION_LANGUAGES map[string]string — 13 种语言
DEFAULT/MIN/MAX_COVER_DEAD_ZONE_WIDTH int
4. CA 证书常量:
MIHOME_CA_CERT_STR string — 两段 PEM 证书(用反引号多行字符串)
MIHOME_CA_CERT_SHA256 string
### 注意事项
- 无外部依赖,可独立编译
- Go 不支持类型混合的常量组,数值单独一组,字符串单独一组
- 路径常量(如文件路径)用 Go 的 os.Getenv 或相对路径,不对齐 Python 的字面值
```
---
## 任务 1.3 — common.py → common.go
```
## 任务:移植 MIoT 通用工具
源文件:D:\miot\py-miot\common.py (189行)
目标文件:D:\miot\go-miot\common.go (新建)
参考子文档:D:\miot\go-miot\migration\06-miot-utils.md
### 需实现的内容
1. 工具函数(全部为包级公开函数):
- GenAbsolutePath(relativePath string) string — path.Join
- CalcGroupID(uid, homeID string) string — SHA1 取前 16 位 hex
- LoadJSONFile(filePath string) (map[string]interface{}, error)
- LoadYAMLFile(filePath string) (map[string]interface{}, error)
- RandomizeInt(value int, ratio float64) int
- RandomizeFloat(value float64, ratio float64) float64
- SlugifyName(name string) string — 可用 github.com/gosimple/slug
- SlugifyDID(cloudServer, did string) string — f"{cloudServer}_{did}" 后 slugify
2. MIoTHttp 工具类(可选,如已有 http_client.go 则跳过):
- Get(url string, params, headers map[string]string) (string, error)
- GetJSON(url string, params, headers map[string]string) (map[string]interface{}, error)
- Post / PostJSON 同理
3. MIoTMatcher(可选,评估是否需要 MQTT topic 匹配功能)
### 依赖
- encoding/json, encoding/yaml (或 gopkg.in/yaml.v3)
- crypto/sha1, encoding/hex
- github.com/gosimple/slug (可选)
- path/filepath, io/ioutil
### 注意事项
- 如果 go-miot 已有 http_client.go,HTTP 部分可跳过
- Slugify 如果用第三方库,需要在 go.mod 中添加依赖
```
---
## 任务 1.4 — miot_storage.py → miot_storage.go
```
## 任务:移植 MIoT 存储系统
源文件:D:\miot\py-miot\miot_storage.py (789行)
目标文件:D:\miot\go-miot\miot_storage.go (新建)
依赖:miot_error.go, const.go
参考子文档:D:\miot\go-miot\migration\05-miot-storage.md
### 需实现的内容
1. MIoTStorage 结构体和方法:
- 字段:rootPath string, mu sync.RWMutex
- Load(domain, name string) ([]byte, error) — 读取文件
- Save(domain, name string, data interface{}) error — 支持 []byte/string/map/slice
- Remove(domain, name string) error
- RemoveDomain(domain string) error — 递归删除目录
- FileExists(domain, name string) bool
- SaveFile / LoadFile — 二进制原始读写(不加哈希)
- Clear() error — 清空所有存储
- 路径格式:{rootPath}/{domain}/{name}
2. 文件完整性:
- Save 时将 SHA256 哈希追加到文件末尾 (32 bytes)
- Load 时校验哈希,不一致返回 error
3. 异步支持:
- 用 goroutine + channel 实现异步方法(LoadAsync, SaveAsync 等)
- 注意并发安全(RWMutex)
4. 用户配置管理(可选,如果不需要可跳过):
- UpdateUserConfig / LoadUserConfig
5. MIoTCert 证书管理(可选,P0 阶段可以仅定义结构体):
- 证书加载、验证、生成 CSR 等方法可后续实现
### 注意事项
- Python 的 async/await → Go 的 goroutine + channel
- Python 的 asyncio.run_in_executor → Go 直接用 goroutine
- 文件路径用 filepath.Join,Windows 兼容
- 哈希校验失败返回明确错误
```
---
## 任务 1.5 — miot_cloud.py → miot_cloud.go
```
## 任务:移植 MIoT 云端 HTTP 客户端
源文件:D:\miot\py-miot\miot_cloud.py (714行)
目标文件:D:\miot\go-miot\miot_cloud.go (新建)
依赖:miot_error.go, const.go, common.go
参考子文档:D:\miot\go-miot\migration\03-miot-cloud.md
### 需实现的内容
1. MIoTOauthClient 结构体(OAuth 授权客户端):
- 字段:clientID int64, redirectURL, oauthHost, deviceID, state string
- 构造函数 NewMIoTOauthClient(clientID, redirectURL, cloudServer, uuid string)
- GenAuthURL() — 生成授权 URL(URL 编码参数拼接)
- GetAccessToken(code string) (map[string]interface{}, error)
- RefreshAccessToken(refreshToken string) (map[string]interface{}, error)
- Close() — 关闭 HTTP 连接
- token 过期时间计算:expires_ts = time.Now() + expires_in*0.7
2. MIoTHttpClient 结构体(云端 API 客户端):
- 字段:host, baseURL, clientID, accessToken string
- 构造函数 NewMIoTHttpClient(cloudServer, clientID, accessToken string)
- UpdateHTTPHeader(cloudServer, clientID, accessToken string)
- HTTP 请求头设置:X-Client-BizId=haapi, Authorization=Bearer{token}
3. 核心 API 方法:
- GetUserInfo() — 获取用户信息
- GetHomeInfos() — 获取家庭信息(支持分页)
- GetDevices(homeIDs []string) — 获取设备列表(合并设备信息和家庭/房间归属)
- GetDevicesWithDIDs(dids []string) — 按 DID 批量获取设备
- GetProps(params []map) — 批量获取设备属性
- GetCentralCert(csr string) — 获取中央证书
- GetSeparatedSharedDevices() — 获取共享设备
- GetUID() — 获取用户 UID
4. 内部辅助方法:
- __mihome_api_get(urlPath, params) — GET 请求(处理 401/非200 状态码)
- __mihome_api_post(urlPath, data) — POST 请求
- __get_dev_room_page(maxID) — 分页获取设备和房间信息
- __get_device_list_page(dids, startDID) — 分页获取设备列表
### API 端点(关键):
POST /app/v2/ha/oauth/get_token — OAuth token
POST /app/v2/homeroom/gethome — 获取家庭
POST /app/v2/homeroom/get_dev_room_page — 设备房间分页
POST /app/v2/home/device_list_page — 设备列表分页
POST /app/v2/miotspec/prop/get — 属性批量获取
GET https://open.account.xiaomi.com/user/profile — 用户信息
### 注意事项
- 使用 net/http 标准库
- 设备过滤:跳过 miwifi.* 前缀,跳过 UNSUPPORTED_MODELS
- 分页逻辑:Python 用递归,Go 可以用 for 循环 + break
- Python asyncio.gather → Go sync.WaitGroup + goroutine
- 子设备处理:.s\d+ 后缀的设备合并到父设备
```
---
## 任务 1.6 — miot_client.py → miot_client.go (补全)
```
## 任务:补全 MIoT 客户端
源文件:D:\miot\py-miot\miot_client.py
目标文件:D:\miot\go-miot\miot_client.go (现有,需补全)
参考子文档:D:\miot\go-miot\migration\01-miot-client.md
### 补全检查清单
1. 客户端初始化:
- 构造函数参数:cloudServer, accessToken, clientID, language, loop
- 依赖注入:MIoTHttpClient, MIoTSpecInstance(列表), MIoTStorage, MIoTLan
2. 设备管理:
- 设备发现和注册:从云端获取设备列表,创建 MIoTDevice 实例
- 设备存储:保存/加载设备实例到 storage
3. 属性操作:
- GetProp(did, siid, piid) — 优先本地 MIPS,回退云端
- SetProp(did, siid, piid, value) — 只走云端(或 MIPS if connected)
- 属性缓存和批量刷新
4. 事件订阅:
- 订阅设备事件(MIPS 推送 + 云端轮询)
- 事件回调管理
5. 资源管理:
- Init() — 初始化 MIPS、LAN、云端连接
- Close() — 关闭所有连接,释放资源
- 重连机制
### 关键结构体
type MIoTClient struct {
cloudServer string
accessToken string
clientID string
language string
httpClient *MIoTHttpClient
mipsClient *MIoTMipsClient
lanManager *MIoTLan
storage *MIoTStorage
devices map[string]*MIoTDevice
devMu sync.RWMutex
// ...
}
### 注意事项
- 先读现有 go-miot/miot_client.go,了解已实现的部分
- 只补全缺失功能,不要重写已有代码
- 并发安全(devices map 读写的锁保护)
- 错误处理:所有外部调用都要处理 error
```
---
## 任务 1.7 — miot_device.py → miot_device.go (补全)
```
## 任务:补全 MIoT 设备模型
源文件:D:\miot\py-miot\miot_device.py
目标文件:D:\miot\go-miot\miot_device.go (现有,需补全)
参考子文档:D:\miot\go-miot\migration\02-miot-device.md
### 补全检查清单
1. MIoTDevice 结构体:
- 基本字段:did, name, model, urn, token, ip, online bool
- 制造商字段:manufacturer, icon
- 归属字段:homeID, roomID, homeName, roomName, groupID
- 连接类型:connectType, rssi, ssid, bssid
- 版本:fwVersion
- 子设备:subDevices map[int]*MIoTDevice
- SPEC 引用:serviceList []*MIoTSpecService
2. 设备初始化:
- NewMIoTDevice(client *MIoTClient, did string) *MIoTDevice
- LoadFromCloud(client *MIoTClient, cloudData map) — 从云端数据填充
- LoadSPEC(client *MIoTClient) error — 从 SPEC 解析服务/属性/事件/动作
3. 属性操作:
- GetProp(siid, piid int) (interface{}, error) — 委托给 client.GetProp
- SetProp(siid, piid int, value interface{}) error — 委托给 client.SetProp
- GetFormattedProp(siid, piid int) — 含值格式化和精度处理
4. 设备状态:
- IsOnline() bool
- SetOnline(online bool)
- HasWiFi() — connectType != -1 判断
5. 序列化:
- ToDict() map[string]interface{} — 用于 storage 保存
- FromDict(data map[string]interface{}) *MIoTDevice — 从 storage 加载
### 注意事项
- 先读现有 go-miot/miot_device.go
- SPEC 解析可能依赖 spec_parser.go(尚未完整),先预留接口
- 子设备用指针切片而非递归结构
```
---
## 依赖关系图(第一批内部)
```
┌─────────────┐
│ miot_error │ ← 无依赖
└──────┬──────┘
│
┌────────────────┼────────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ const │ │ common │ │ storage │
└────┬─────┘ └────┬─────┘ └────┬─────┘
│ │ │
└───────────────┼───────────────┘
▼
┌──────────┐
│miot_cloud│
└────┬─────┘
│
┌─────────┴─────────┐
▼ ▼
┌──────────┐ ┌──────────┐
│miot_client│◄─────│miot_device│
└──────────┘ └──────────┘
```
## 执行顺序
1. miot_error (最独立,先做)
2. const (无依赖)
3. common (无依赖)
4. miot_storage (依赖 error)
5. miot_cloud (依赖 error/const/common)
6. miot_client (依赖 cloud/device/storage)
7. miot_device (依赖 client/spec)
```