// Package bridge 提供多用户小米设备管理门面。 // // 外部只需 import 这一个包,无需直接依赖 xiaomi/devices/miot。 // // 用法: // // pool := bridge.NewPool() // pool.Add(ctx, id, uuid, auth, dataDir) // b, _ := pool.Get(id) // ac, _ := b.AC("did") // ac.TurnOn(ctx) // state := ac.GetState() package bridge import ( "context" "fmt" "sync" "xiaomihome/logger" "xiaomihome/xiaomi" "xiaomihome/xiaomi/devices" ) // ── 类型别名:业务层不需要 import devices ── type ( ACState = devices.ACState LightState = devices.LightState FanState = devices.FanState HumidifierState = devices.HumidifierState HeaterState = devices.HeaterState VacuumStatus = devices.VacuumStatus ) // ── Pool ── // Pool 全局路由:id → Bridge。 type Pool struct { mu sync.RWMutex items map[int64]*Bridge } // NewPool 创建 Pool。 func NewPool() *Pool { return &Pool{items: make(map[int64]*Bridge)} } // Get 按 id 查找。 func (p *Pool) Get(id int64) (*Bridge, bool) { p.mu.RLock() defer p.mu.RUnlock() b, ok := p.items[id] return b, ok } // Add 新建并注册一个 Bridge。 func (p *Pool) Add(ctx context.Context, id int64, uuid string, auth xiaomi.AuthInfo, dataDir string, homeIDs []int64) (*Bridge, error) { p.mu.Lock() defer p.mu.Unlock() if _, exists := p.items[id]; exists { return nil, fmt.Errorf("bridge: %d already exists", id) } b, err := newBridge(ctx, id, uuid, auth, dataDir, homeIDs) if err != nil { return nil, err } p.items[id] = b return b, nil } // Remove 移除并关闭。 func (p *Pool) Remove(id int64) error { p.mu.Lock() b, ok := p.items[id] if ok { delete(p.items, id) } p.mu.Unlock() if !ok { return fmt.Errorf("bridge: %d not found", id) } return b.Close() } // Close 关闭所有。 func (p *Pool) Close() { p.mu.Lock() defer p.mu.Unlock() for id, b := range p.items { b.Close() delete(p.items, id) } } // ── Bridge ── // Bridge 封装单个用户的 Client + 类型化设备控制器 + 状态缓存。 type Bridge struct { id int64 client *xiaomi.Client lgr logger.Logger mu sync.RWMutex dv map[string]interface{} // DID → devices.Xxx interface onStateChanged func(id int64, did, deviceType, changed string, state interface{}) } func newBridge(ctx context.Context, id int64, uuid string, auth xiaomi.AuthInfo, dataDir string, homeIDs []int64) (*Bridge, error) { idStr := fmt.Sprintf("%d", id) client, err := xiaomi.NewClient(ctx, xiaomi.Config{ AuthInfo: auth, DataDir: dataDir, UUID: uuid, UID: idStr, HomeIDs: homeIDs, }) if err != nil { return nil, fmt.Errorf("bridge: %w", err) } b := &Bridge{ id: id, client: client, lgr: logger.Default(), dv: make(map[string]interface{}), } devList, err := client.GetDevices(ctx) if err != nil { client.Close() return nil, fmt.Errorf("bridge: GetDevices: %w", err) } for _, info := range devList { d, createErr := devices.Create(client, info) if createErr != nil { continue } b.dv[info.DID] = d } b.lgr.Infof("[bridge] %d: %d devices", id, len(b.dv)) return b, nil } // SetLogger 设置日志记录器。 func (b *Bridge) SetLogger(l logger.Logger) { b.lgr = l } func (b *Bridge) Close() error { return b.client.Close() } // Devices 返回设备列表(DID → 类型名)。 func (b *Bridge) Devices() map[string]string { b.mu.RLock() defer b.mu.RUnlock() out := make(map[string]string, len(b.dv)) for did, d := range b.dv { out[did] = deviceTypeName(d) } return out } func deviceTypeName(d interface{}) string { switch d.(type) { case devices.AirConditioner: return "air_conditioner" case devices.Light: return "light" case devices.Switch: return "switch" case devices.Fan: return "fan" case devices.Cover: return "cover" case devices.Humidifier: return "humidifier" case devices.Vacuum: return "vacuum" case devices.WaterHeater: return "water_heater" case devices.Thermostat: return "thermostat" case devices.TempHumiditySensor: return "temp_humidity_sensor" case devices.OccupancySensor: return "occupancy_sensor" case devices.Speaker: return "speaker" default: return "unknown" } } // ── 类型化设备访问器 ── func (b *Bridge) AC(did string) (devices.AirConditioner, error) { d, ok := b.dv[did] if !ok { return nil, fmt.Errorf("bridge: device %s not found", did) } ac, ok := d.(devices.AirConditioner) if !ok { return nil, fmt.Errorf("bridge: device %s is not an AirConditioner", did) } return ac, nil } func (b *Bridge) Light(did string) (devices.Light, error) { d, ok := b.dv[did] if !ok { return nil, fmt.Errorf("bridge: device %s not found", did) } lt, ok := d.(devices.Light) if !ok { return nil, fmt.Errorf("bridge: device %s is not a Light", did) } return lt, nil } func (b *Bridge) Switch(did string) (devices.Switch, error) { d, ok := b.dv[did] if !ok { return nil, fmt.Errorf("bridge: device %s not found", did) } sw, ok := d.(devices.Switch) if !ok { return nil, fmt.Errorf("bridge: device %s is not a Switch", did) } return sw, nil } func (b *Bridge) Fan(did string) (devices.Fan, error) { d, ok := b.dv[did] if !ok { return nil, fmt.Errorf("bridge: device %s not found", did) } f, ok := d.(devices.Fan) if !ok { return nil, fmt.Errorf("bridge: device %s is not a Fan", did) } return f, nil } func (b *Bridge) Cover(did string) (devices.Cover, error) { d, ok := b.dv[did] if !ok { return nil, fmt.Errorf("bridge: device %s not found", did) } cv, ok := d.(devices.Cover) if !ok { return nil, fmt.Errorf("bridge: device %s is not a Cover", did) } return cv, nil } func (b *Bridge) Humidifier(did string) (devices.Humidifier, error) { d, ok := b.dv[did] if !ok { return nil, fmt.Errorf("bridge: device %s not found", did) } h, ok := d.(devices.Humidifier) if !ok { return nil, fmt.Errorf("bridge: device %s is not a Humidifier", did) } return h, nil } func (b *Bridge) Vacuum(did string) (devices.Vacuum, error) { d, ok := b.dv[did] if !ok { return nil, fmt.Errorf("bridge: device %s not found", did) } v, ok := d.(devices.Vacuum) if !ok { return nil, fmt.Errorf("bridge: device %s is not a Vacuum", did) } return v, nil } func (b *Bridge) WaterHeater(did string) (devices.WaterHeater, error) { d, ok := b.dv[did] if !ok { return nil, fmt.Errorf("bridge: device %s not found", did) } wh, ok := d.(devices.WaterHeater) if !ok { return nil, fmt.Errorf("bridge: device %s is not a WaterHeater", did) } return wh, nil } func (b *Bridge) Thermostat(did string) (devices.Thermostat, error) { d, ok := b.dv[did] if !ok { return nil, fmt.Errorf("bridge: device %s not found", did) } t, ok := d.(devices.Thermostat) if !ok { return nil, fmt.Errorf("bridge: device %s is not a Thermostat", did) } return t, nil } func (b *Bridge) TempHumidity(did string) (devices.TempHumiditySensor, error) { d, ok := b.dv[did] if !ok { return nil, fmt.Errorf("bridge: device %s not found", did) } s, ok := d.(devices.TempHumiditySensor) if !ok { return nil, fmt.Errorf("bridge: device %s is not a TempHumiditySensor", did) } return s, nil } func (b *Bridge) Occupancy(did string) (devices.OccupancySensor, error) { d, ok := b.dv[did] if !ok { return nil, fmt.Errorf("bridge: device %s not found", did) } s, ok := d.(devices.OccupancySensor) if !ok { return nil, fmt.Errorf("bridge: device %s is not an OccupancySensor", did) } return s, nil } func (b *Bridge) Speaker(did string) (devices.Speaker, error) { d, ok := b.dv[did] if !ok { return nil, fmt.Errorf("bridge: device %s not found", did) } sp, ok := d.(devices.Speaker) if !ok { return nil, fmt.Errorf("bridge: device %s is not a Speaker", did) } return sp, nil }