// Package main demonstrates the SPEC parser's independent usage — resolving device // // properties, events, and actions without requiring a device to be online. // // 运行前提:已配置环境变量 XIAOMI_CLIENT_ID / XIAOMI_CLIENT_SECRET / XIAOMI_ACCESS_TOKEN。 package main import ( "context" "log" "time" "xiaomihome/miot" "xiaomihome/xiaomi" miotconfig "xiaomihome/miot/examples/config" "xiaomihome/xiaomi/specs" ) func main() { ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() // 1. 加载配置 cfg, err := miotconfig.LoadConfig("../../../miot/examples/config.json") if err != nil { log.Fatal("请先运行 miot/examples/cloud_oauth 获取 token:", err) } client, err := xiaomi.NewClient(ctx, xiaomi.Config{ ClientSecret: "", AccessToken: cfg.AuthInfo.AccessToken, UID: cfg.UID, UUID: cfg.UUID, }) if err != nil { log.Fatal(err) } defer client.Close() // 3. 获取全部设备 allDevices, err := client.GetDevices(ctx) if err != nil { log.Fatal("获取设备列表失败:", err) } if len(allDevices) == 0 { log.Fatal("未找到任何设备") } // 4. 创建 SPEC 解析器(需要存储目录用于缓存 SPEC 文件) storage := miot.NewMIoTStorage("./data") parser := miot.NewMIoTSpecParser(miot.DEFAULT_INTEGRATION_LANGUAGE, storage, "./data") // 5. 对每个设备解析 SPEC 并打印属性/事件/动作 for _, dev := range allDevices { if dev.URN == "" || dev.Model == "" { continue } log.Printf("=== %s (型号: %s) ===", dev.Name, dev.Model) log.Printf(" URN: %s", dev.URN) specInst, err := parser.Parse(dev.URN, dev.Model) if err != nil { log.Printf(" 解析 SPEC 失败: %v", err) continue } resolver := specs.NewPropertyResolver(specInst) log.Printf(" 服务数: %d", len(specInst.Services)) for _, svc := range specInst.Services { log.Printf(" --- 服务 %d: %s (%s) ---", svc.IID, svc.Type, svc.Description) // 属性 if len(svc.Properties) > 0 { log.Printf(" 属性 (%d 个):", len(svc.Properties)) for _, prop := range svc.Properties { access := accessStr(prop.Access) log.Printf(" [%d/%d] %s type=%s format=%s access=%s", prop.SIID, prop.PIID, prop.Description, prop.Type, prop.Format, access) } } // 事件 if len(svc.Events) > 0 { log.Printf(" 事件 (%d 个):", len(svc.Events)) for _, evt := range svc.Events { log.Printf(" [%d/%d] %s args=%v", evt.SIID, evt.EIID, evt.Type, evt.Arguments) } } // 动作 if len(svc.Actions) > 0 { log.Printf(" 动作 (%d 个):", len(svc.Actions)) for _, act := range svc.Actions { log.Printf(" [%d/%d] %s in=%v out=%v", act.SIID, act.AIID, act.Type, act.In, act.Out) } } } // 演示 resolver 查找 log.Printf(" --- Resolver 查找示例 ---") if siid, piid, found := resolver.FindByType("on"); found { log.Printf(" FindByType(\"on\"): siid=%d piid=%d ok", siid, piid) } else { log.Printf(" FindByType(\"on\"): not found") } if siid, piid, found := resolver.FindByType("mode"); found { log.Printf(" FindByType(\"mode\"): siid=%d piid=%d ok", siid, piid) } if siid, piid, found := resolver.FindByType("temperature"); found { log.Printf(" FindByType(\"temperature\"): siid=%d piid=%d ok", siid, piid) } if siid, piid, found := resolver.FindByType("brightness"); found { log.Printf(" FindByType(\"brightness\"): siid=%d piid=%d ok", siid, piid) } if siid, piid, found := resolver.FindByType("color-temperature"); found { log.Printf(" FindByType(\"color-temperature\"): siid=%d piid=%d ok", siid, piid) } if siid, piid, found := resolver.FindByType("target-temperature"); found { log.Printf(" FindByType(\"target-temperature\"): siid=%d piid=%d ok", siid, piid) } if siid, piid, found := resolver.FindByType("fan-level"); found { log.Printf(" FindByType(\"fan-level\"): siid=%d piid=%d ok", siid, piid) } } log.Println("SPEC 解析器演示完毕") } func contains(slice []string, s string) bool { for _, v := range slice { if v == s { return true } } return false } func accessStr(access []string) string { readable := contains(access, "read") writable := contains(access, "write") if readable && writable { return "rw" } if readable { return "r" } if writable { return "w" } return "" }