# xiaomi — Xiaomi 智能家居 Go SDK 高级封装层 `xiaomihome/xiaomi` 是 `xiaomihome/miot` 的强类型上层封装,将底层 `map[string]interface{}` API 转换为主流 Go 风格的 struct + interface,并提供设备控制抽象,隐藏 siid/piid 细节。 ## 快速开始 ```go import ( "xiaomihome/miot" "xiaomihome/xiaomi" "xiaomihome/xiaomi/devices" ) // 1. 创建底层 miot 客户端 miotClient := miot.NewMIoTClient("phone", entryData, "", "cn", miot.CtrlModeAuto) miotClient.Init() // 2. 创建 HTTP 客户端 httpClient, _ := miot.NewMIoTHttpClient(cloudServer, clientID, accessToken) // 3. 包装为 xiaomi.Client client := xiaomi.NewClient(miotClient, httpClient) ``` ## API 参考 ### Client 主入口 (`client.go`) ```go client := xiaomi.NewClient(inner *miot.MIoTClient, httpClient *miot.MIoTHttpClient) client.Inner() // 返回底层 MIoTClient client.HTTPClient() // 返回底层 MIoTHttpClient ``` ### 用户信息 (`user.go`) ```go user, err := client.GetUserInfo() // → *UserInfo{UID, NickName, AvatarURL} ``` ### 家庭/房间 (`homes.go`) ```go homes, err := client.GetHomeList() // → []*HomeInfo home, err := client.GetHome(homeID) // → *HomeInfo (含房间列表) rooms, err := client.GetRooms(homeID) // → []*RoomInfo dids, err := client.GetRoomDevices(homeID, roomID) // → []string ``` **HomeInfo 结构:** | 字段 | 类型 | 说明 | |------|------|------| | ID | `string` | 家庭 ID | | Name | `string` | 家庭名称 | | UID | `string` | 用户 ID | | GroupID | `string` | MIPS 分组 ID | | Rooms | `[]RoomInfo` | 房间列表 | | DidList | `[]string` | 所有设备 DID | | ShareState | `bool` | 是否为共享家庭 | ### 设备列表 (`devices.go`) ```go devices, err := client.GetDevices(opts...) // → []*DeviceInfo device, err := client.GetDevice(did) // → *DeviceInfo err := client.RefreshDevices() // 强制刷新设备列表 ``` **过滤器(组合使用):** ```go // 只获取在线设备 client.GetDevices(xiaomi.FilterByOnline()) // 指定家庭 + 在线 client.GetDevices( xiaomi.FilterByHome("home001"), xiaomi.FilterByOnline(), ) // 指定房间 client.GetDevices(xiaomi.FilterByRoom("room001")) // 指定型号 client.GetDevices(xiaomi.FilterByModel("xiaomi.aircondition.c1")) ``` ### 属性读写 (`properties.go`) ```go prop, err := client.GetProp(did, siid, piid) // → *PropertyValue err := client.SetProp(did, siid, piid, value) props, err := client.GetProps([]PropKey{...}) // → []*PropertyValue results, err := client.SetProps([]PropKeyValue{...}) // → []*PropResult ``` ### Action 调用 (`actions.go`) ```go result, err := client.Action(did, siid, aiid, params) // → *ActionResult ``` ### 订阅通知 (`subscribe.go`) ```go // 属性变化订阅 subID, err := client.SubProp(did, siid, piid, func(did string, prop *PropertyValue) { fmt.Printf("属性变化: %v\n", prop.Value) }) // 取消属性订阅 client.UnsubProp(did, subID) // 事件订阅 subID, err := client.SubEvent(did, siid, eiid, func(did string, event *EventOccurred) { fmt.Printf("事件: %v\n", event.Arguments) }) client.UnsubEvent(did, subID) // 设备在线状态订阅 client.SubDeviceState(did, func(did string, state xiaomi.DeviceState) { if state == xiaomi.StateOnline { fmt.Println("设备上线") } }) client.UnsubDeviceState(did) ``` ### 设备控制抽象 (`devices/`) #### 基础能力 (`BaseDevice`) 所有设备控制对象共享的基础方法: ```go d.DID() // 设备 ID d.Name() // 设备名称 d.Model() // 设备型号 d.Online() // 是否在线 d.Info() // 完整设备信息 *DeviceInfo d.GetProp(siid, piid) // 读取属性 d.SetProp(siid, piid, value) // 写入属性 d.Action(siid, aiid, params) // 调用 Action d.SubProp(siid, piid, handler) // 订阅属性变化 d.SubDeviceState(handler) // 订阅在线状态 ``` #### 开关 (`Switch`) ```go sw, _ := devices.NewSwitch(client, info) sw.TurnOn() sw.TurnOff() sw.Toggle() on, _ := sw.IsOn() // 订阅状态变化 sw.OnStateChanged(func(on bool) { ... }) ``` #### 灯光 (`Light`) ```go light, _ := devices.NewLight(client, info) light.TurnOn() / TurnOff() / Toggle() light.SetBrightness(80) // 1-100 b, _ := light.GetBrightness() light.SetColorTemp(4000) // 2700-6500K k, _ := light.GetColorTemp() light.SetColor(255, 0, 0) // RGB 0-255 r, g, b, _ := light.GetColor() light.OnStateChanged(func(state LightState) { ... }) ``` #### 空调 (`AirConditioner`) ```go ac, _ := devices.NewAirConditioner(client, info) // 基础 ac.TurnOn() / TurnOff() on, _ := ac.IsOn() // 模式 ac.SetMode(devices.ModeCool) // Cool/Heat/Fan/Dry/Auto mode, _ := ac.GetMode() // 温度 ac.SetTargetTemp(26.0) target, _ := ac.GetTargetTemp() current, _ := ac.GetCurrentTemp() // 风速 ac.SetFanSpeed(devices.SpeedAuto) // Low/Medium/High/Auto speed, _ := ac.GetFanSpeed() // 摆风 ac.SetSwing(devices.SwingBoth) // Off/Vertical/Horizontal/Both swing, _ := ac.GetSwing() // 湿度(部分支持) ac.SetTargetHumidity(50) ac.GetTargetHumidity() ac.GetCurrentHumidity() // 电辅热 / 节能(部分支持) ac.SetAuxHeat(true) ac.SetEco(true) ac.OnStateChanged(func(state ACState) { ... }) ``` #### 风扇 (`Fan`) ```go fan, _ := devices.NewFan(client, info) fan.TurnOn() / TurnOff() fan.SetFanLevel(2) // 1-4 档位 fan.SetOscillation(true) // 摇头 fan.SetNaturalWind(true) // 自然风 ``` #### 窗帘 (`Cover`) ```go cover, _ := devices.NewCover(client, info) cover.Open() / Close() / Stop() cover.SetPosition(50) // 0=全关, 100=全开 pos, _ := cover.GetPosition() ``` #### 加湿器 (`Humidifier`) ```go h, _ := devices.NewHumidifier(client, info) h.TurnOn() / TurnOff() h.SetTargetHumidity(60) h.SetFanLevel(2) ``` #### 扫地机 (`Vacuum`) ```go v, _ := devices.NewVacuum(client, info) v.Start() / Stop() v.ReturnToDock() v.SetFanLevel(3) // 吸力档位 status, _ := v.GetStatus() // → VacuumStatus{On, Mode, FanLevel, Battery} ``` #### 热水器 (`WaterHeater`) ```go wh, _ := devices.NewWaterHeater(client, info) wh.TurnOn() / TurnOff() wh.SetTargetTemp(45.0) wh.GetCurrentTemp() ``` #### 温控器 (`Thermostat`) ```go t, _ := devices.NewThermostat(client, info) t.TurnOn() / TurnOff() t.SetTargetTemp(22.0) t.SetHeating(true) ``` #### 工厂函数 (`factory.go`) 自动根据设备 URN 创建对应的控制接口: ```go for _, info := range deviceList { ctrl, err := devices.Create(client, info) if err != nil || ctrl == nil { continue } switch d := ctrl.(type) { case devices.Switch: d.TurnOn() case devices.Light: d.SetBrightness(80) case devices.AirConditioner: d.SetTargetTemp(26.0) case devices.Fan: d.SetFanLevel(2) case devices.Cover: d.Open() case devices.Humidifier: d.SetTargetHumidity(60) case devices.Vacuum: d.Start() case devices.WaterHeater: d.SetTargetTemp(45.0) case devices.Thermostat: d.SetTargetTemp(22.0) } } ``` ### SPEC 解析器 (`specs/`) 用于直接从设备 SPEC 中按功能语义查找 siid/piid: ```go resolver := specs.NewPropertyResolver(spec) siid, piid, ok := resolver.FindByType("on") // 按属性类型 piid, ok := resolver.FindByFormat("bool", siid) // 按数据格式 siid, piid, ok := resolver.FindByDescription("开关") // 按描述 aiid, ok := resolver.FindAction(siid, "toggle") // 按 Action 类型 props := resolver.GetAllProperties(siid) // 获取某服务所有属性 prop := resolver.GetProperty(siid, piid) // 获取单个属性 ``` ## 错误处理 所有错误都实现了 Go 标准 `error` 接口,同时可通过 `errors.Is` 判断: ```go if errors.Is(err, xiaomi.ErrDeviceOffline) { ... } if errors.Is(err, xiaomi.ErrNotSupported) { ... } // ClientError 携带操作上下文 var ce *xiaomi.ClientError if errors.As(err, &ce) { fmt.Println("操作:", ce.Op, "设备:", ce.DID) } ``` ## 关于 siid/piid 如果你需要直接操作底层属性,xiaomi 封装层仍支持传统的 siid/piid 方式: ```go // 读取空调开关 (常见 siid=2, piid=1) prop, _ := client.GetProp("did", 2, 1) // 写入目标温度 client.SetProp("did", 2, 3, 26.0) ``` 但强烈推荐使用设备控制抽象,它会自动从 SPEC 解析正确的 siid/piid。 ## 完整示例 参见 [`examples/main.go`](examples/main.go)。