Files
xiaomihome/xiaomi/migration/EXAMPLES_PLAN.md
T
4566704 a3d94c4b9f chore: 提交高层 xiaomi 封装库及示例
- 新增 xiaomi/examples/ 下 8 个示例程序(用户/家庭查询、设备列表、开关/灯光/空调控制、属性订阅、高级过滤分类、SPEC 解析)
- miot_client_sub.go: 重构 SubProp/SubEvent,使用 buildPropTopic/buildEventTopic 支持通配符订阅(siid/piid=0 → +),并修复锁顺序问题(将 RequestRefreshProp 移到 Lock 外)
- spec_parser.go: 新增 downloadSpecFile 方法,本地 SPEC 文件缺失时自动从 miot-spec.org 下载
- ARCH_PLAN.md: 架构设计从 Proposed 更新为 Accepted(v1.0→v1.1),补充设备分类/工厂/SPEC 映射等模块设计
- xiaomi/: 新增 miot 上层强类型封装模块,包含 Client 主入口、用户/家庭/设备 API、属性读写、动作调用、订阅通知,以及 devices/ 设备控制抽象(Switch/Light/AirConditioner/Fan/Cover/Humidifier/Vacuum/WaterHeater/Thermostat)和 specs/ SPEC 查询辅助
- 更多 xiaomi 示例(风扇/窗帘/传感器控制)
2026-06-29 08:51:21 +08:00

320 lines
9.3 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.
# xiaomi 封装层示例程序规划
> 状态:Completed | 版本:v1.0 | 日期:2026-06-28 | 完成日期:2026-06-29
---
## 一、现状分析
### 已有示例
| 文件 | 状态 | 问题 |
|------|------|------|
| `xiaomi/examples/main.go` | 存在(224 行) | 几乎全是 `fmt.Println` 伪代码,非可运行的完整示例 |
### 目标
对标 `ARCH_PLAN.md` v1.1 的最终形态,覆盖完整 API 面,每个示例独立可理解、贴近实战。
---
## 二、示例架构
```
xiaomi/examples/
├── 01_user_home/ # 用户 + 家庭 + 房间信息
│ └── main.go
├── 02_device_list/ # 设备列表 + 过滤
│ └── main.go
├── 03_switch_control/ # 开关控制
│ └── main.go
├── 04_light_control/ # 灯光控制
│ └── main.go
├── 05_ac_control/ # 空调控制
│ └── main.go
├── 06_fan_cover/ # 风扇 + 窗帘控制
│ └── main.go
├── 07_prop_subscribe/ # 属性/事件/状态订阅
│ └── main.go
├── 08_adv_filter_classify/ # 高级过滤 + 分类 + 工厂
│ └── main.go
├── 09_spec_parser/ # SPEC 解析器独立使用(已有完整代码)
│ └── main.go
└── config/ # 共享配置模块(敏感信息统一管理)
└── config.go
```
---
## 三、各示例详述
### 01_user_home — 用户/家庭/房间信息
**覆盖 API**:
- `client.GetUserInfo(ctx)` → `*UserInfo`
- `client.GetHomeList(ctx)` → `[]*HomeInfo`(含经纬度、地址)
- `client.GetHome(ctx, homeID)` → `*HomeInfo`
- `client.GetRooms(ctx, homeID)` → `[]*RoomInfo`
- `client.GetRoomDevices(ctx, homeID, roomID)` → `[]string`
**演示重点**:
- context.WithTimeout 控制超时
- HomeInfo 的地里位置字段(CityID, Longitude, Latitude, Address)
- for-range 遍历家庭→房间→设备层级结构
---
### 02_device_list — 设备列表与过滤
**覆盖 API**:
- `client.GetDevices(ctx, opts...)` → `[]*DeviceInfo`
- `client.GetDevice(ctx, did)` → `*DeviceInfo`
- `client.RefreshDevices(ctx)` → error
- `FilterByHome` / `FilterByRoom` / `FilterByOnline` / `FilterByModel` / `FilterByKind`
- `DeviceInfo.DeviceKind()` 分类
**演示重点**:
- 多种过滤组合(在线+客厅、按型号、按种类)
- DeviceKind() 输出
- RefreshDevices 刷新时机
---
### 03_switch_control — 开关控制
**覆盖 API**:
- `devices.Create(client, info)` 工厂 → `Switch`
- `Switch.{TurnOn, TurnOff, Toggle, IsOn}(ctx)`
- `Switch.OnStateChanged(handler)` 状态订阅
**演示重点**:
- 工厂创建单设备
- TurnOn/TurnOff/Toggle 完整链路
- IsOn 状态查询
- OnStateChanged 回调演示
---
### 04_light_control — 灯光控制
**覆盖 API**:
- `Light.{TurnOn, TurnOff, Toggle}(ctx)`
- `Light.{SetBrightness, GetBrightness}(ctx, pct)`
- `Light.{SetColorTemp, GetColorTemp}(ctx, kelvin)`
- `Light.{SetColor, GetColor}(ctx, r, g, b)`
- `Light.OnStateChanged(handler)`
**演示重点**:
- 亮度 0-100 调节
- 色温 2700K-6500K 调节
- RGB 颜色控制
- 不支持功能的降级处理(`GetBrightness` 返回 -1 → 跳过)
---
### 05_ac_control — 空调控制
**覆盖 API**:
- `AirConditioner.{TurnOn, TurnOff, IsOn}(ctx)`
- `SetMode(ctx, ACMode)` / `GetMode(ctx)` — cool/heat/dry/fan/auto
- `SetTargetTemp(ctx, celsius)` / `GetTargetTemp(ctx)` / `GetCurrentTemp(ctx)`
- `SetFanSpeed(ctx, FanSpeed)` / `GetFanSpeed(ctx)` — low/medium/high/auto
- `SetSwing(ctx, SwingMode)` / `GetSwing(ctx)` — off/vertical/horizontal/both
- `SetTargetHumidity(ctx, pct)` / `GetTargetHumidity(ctx)` / `GetCurrentHumidity(ctx)`
- `SetAuxHeat(ctx, on)` / `GetAuxHeat(ctx)`
- `SetEco(ctx, on)` / `GetEco(ctx)`
- `OnStateChanged(handler)` → `ACState`
**演示重点**:
- 完整空调控制链路(开→设制冷→设26°C→自动风速→垂直摆风)
- OnStateChanged 实时状态回调
- 不支持的功能优雅降级(如无湿度传感器,跳过湿度设置)
---
### 06_fan_cover — 风扇 + 窗帘控制
**覆盖 API**:
- `Fan.{TurnOn, TurnOff, SetSpeed, SetOscillation, SetNaturalWind}(ctx)`
- `Cover.{Open, Close, Stop, SetPosition, GetPosition}(ctx)`
**演示重点**:
- 风扇 4 档调速 + 摇头 + 自然风切换
- 窗帘百分比定位(0%=关, 100%=全开, 50%=半开)
- Cover 的 Open/Close/Stop 语义对比 SetPosition
---
### 07_prop_subscribe — 属性/事件/状态订阅
**覆盖 API**:
- `client.SubProp(did, siid, piid, PropHandler)` → subID
- `client.UnsubProp(did, subID)`
- `client.SubEvent(did, siid, eiid, EventHandler)` → subID
- `client.UnsubEvent(did, subID)`
- `client.SubDeviceState(did, DeviceStateHandler)`
- `client.UnsubDeviceState(did)`
**演示重点**:
- 订阅前后属性值对比
- 等待N秒展示属性/事件推送
- 取消订阅后不再收到回调
- 设备上下线状态监听
---
### 08_adv_filter_classify — 高级过滤 + 分类 + 工厂模式
**覆盖 API**:
- `devices.Classify(info)` → `Kind` 枚举
- `FilterByKind(kind)` 过滤器
- `devices.Create(client, info)` 工厂 → 各设备接口
- `devices.Kind` 所有枚举值
**演示重点**:
- 获取全部设备 → 按 Kind 分类 → 统计各类型数量
- 工厂批量创建:遍历 DeviceInfo → Create → type switch 分流
- 不支持的设备返回 nil → continue 跳过
- 输出表格:"设备名 | 型号 | 种类 | 状态"
---
### 09_spec_parser — SPEC 解析器独立使用
**覆盖 API**:
- specs 包全部公开 API(如果 specs 是公开的)
- SPEC 属性/事件/动作的枚举和查询
**演示重点**:
- 无需设备在线即可解析 SPEC
- 打印设备有哪些属性(text/switch/select/number/sensor)
- 打印设备有哪些事件和动作
---
## 四、共享配置模块 `config/config.go`
```go
package config
type Config struct {
ClientID string
ClientSecret string
AccessToken string // OAuth token(从环境变量或文件读取)
}
// LoadFromEnv 从环境变量加载配置
func LoadFromEnv() (*Config, error)
// LoadFromFile 从 JSON 文件加载配置
func LoadFromFile(path string) (*Config, error)
```
**设计原则**:
- 所有示例复用一个 config 加载逻辑,避免重复
- 仅 3 个字段,对应 xiaomi.Config
- 敏感信息从环境变量或文件读取,不硬编码
---
## 五、编码规范
### 5.1 统一约定
```
1. 每个示例的 main() 必须有 context.WithTimeout(30s)
2. 所有 IO 操作带 ctx
3. 错误必须处理(不忽略 err)
4. defer cancel() 放在 func main() 顶部
5. 日志用 log 包,不用 fmt.Print(方便区分日志级别)
6. 每个示例一句话说明功能(注释在 main 函数上方)
```
### 5.2 模板骨架
```go
// Package main demonstrates <功能简述>.
// 运行前提:已配置环境变量 XIAOMI_CLIENT_ID / XIAOMI_CLIENT_SECRET / XIAOMI_ACCESS_TOKEN。
package main
import (
"context"
"log"
"time"
"xiaomihome/xiaomi"
"xiaomihome/xiaomi/devices"
"xiaomihome/xiaomi/examples/config"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
// 1. 加载配置
cfg, err := config.LoadFromEnv()
if err != nil {
log.Fatal("配置加载失败:", err)
}
// 2. 创建客户端(零 miot 引用)
client, err := xiaomi.NewClient(ctx, xiaomi.Config{
ClientID: cfg.ClientID,
ClientSecret: cfg.ClientSecret,
AccessToken: cfg.AccessToken,
})
if err != nil {
log.Fatal("创建客户端失败:", err)
}
defer client.Close()
// 3. 业务逻辑(根据示例不同)
// ...
}
```
---
## 六、与 ARCH_PLAN.md 的对应关系
| ARCH_PLAN.md 目标 | 对应示例 |
|-------------------|---------|
| 用户/家庭/房间信息(GetUserInfo / GetHomeList) | 01_user_home |
| 设备列表 + Filter | 02_device_list |
| Switch 控制 + OnStateChanged | 03_switch_control |
| Light 控制 | 04_light_control |
| AirConditioner 完整控制 | 05_ac_control |
| Fan / Cover 控制 | 06_fan_cover |
| SubProp / SubEvent / SubDeviceState 订阅 | 07_prop_subscribe |
| Classify / FilterByKind / Create 工厂 | 08_adv_filter_classify |
| SPEC 解析器 | 09_spec_parser |
| context.Context + 错误处理 | 全部示例 |
---
## 七、实施计划
| 序号 | 示例 | 文件 | 优先级 | 复杂度 |
|------|------|------|--------|--------|
| 0 | config 共享模块 | `config/config.go` | P0 | 小 |
| 1 | 用户/家庭/房间 | `01_user_home/main.go` | P0 | 小 |
| 2 | 设备列表+过滤 | `02_device_list/main.go` | P0 | 中 |
| 3 | 开关控制 | `03_switch_control/main.go` | P0 | 小 |
| 4 | 灯光控制 | `04_light_control/main.go` | P0 | 中 |
| 5 | 空调控制 | `05_ac_control/main.go` | P0 | 大 |
| 6 | 风扇+窗帘 | `06_fan_cover/main.go` | P1 | 中 |
| 7 | 订阅通知 | `07_prop_subscribe/main.go` | P1 | 大 |
| 8 | 高级过滤+工厂 | `08_adv_filter_classify/main.go` | P1 | 中 |
| 9 | SPEC 解析 | `09_spec_parser/main.go` | P2 | 小 |
| — | 统一 README | `examples/README.md` | P2 | 小 |
---
## 八、与现有 main.go 的关系
现有 `xiaomi/examples/main.go` 将被**替换**为上述 9 个独立示例。如果作为归档保留,可移到 `examples/_archive/main_old.go`。
---
*本文档已全部实施完成。*