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

14 KiB
Raw Permalink Blame History

第一批移植任务提示词 (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)