Files
xiaomihome/miot/BATCH1_TASKS.md
T
4566704 3a44cb9e6a feat: 初始化小米 IoT (MIoT) 智能家居 Go 库
- 实现 MIoT 客户端核心功能(MQTT 连接、设备管理、属性读写)
- 支持云端 API 调用与局域网设备发现(mDNS)
- 集成国际化(i18n)多语言支持
- 添加 MIoT 设备规约解析器(spec_parser)
- 包含单元测试与使用示例
2026-06-28 22:05:49 +08:00

380 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 第一批移植任务提示词 (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)
```