package devices import ( "context" "fmt" "git.zeroonesoft.cn/golib/xiaomihome/xiaomi" ) // Plug 插座/插头统一控制接口(电脑开机卡、智能插座等)。 type Plug interface { Device TurnOn(ctx context.Context) error TurnOff(ctx context.Context) error IsOn(ctx context.Context) (bool, error) OnPropsChanged(handler func(on bool)) (string, error) GetProps() PlugProps FetchProps(ctx context.Context) (PlugProps, error) } // PlugProps 插座完整状态。 type PlugProps struct { On bool `json:"on"` } type plugDevice struct { BaseDevice propOn siidPiid propsCache PlugProps } // NewPlug creates a Plug control for the given device. func NewPlug(client *xiaomi.Client, info *xiaomi.DeviceInfo) (Plug, error) { if info == nil { return nil, xiaomi.ErrDeviceNotFound } miotDev := client.GetMIoTDevice(info.DID) if miotDev == nil || miotDev.SpecInstance() == nil { return nil, fmt.Errorf("%w: device has no SPEC", xiaomi.ErrNotSupported) } d := &plugDevice{ BaseDevice: NewBaseDevice(client, info), } for _, svc := range miotDev.SpecInstance().Services { for _, prop := range svc.Properties { if propertyShortName(prop.Type) == "on" && !d.propOn.valid { d.propOn = siidPiid{prop.SIID, prop.PIID, true} } } } if !d.propOn.valid { return nil, fmt.Errorf("%w: no on property", xiaomi.ErrNotSupported) } return d, nil } func (d *plugDevice) TurnOn(ctx context.Context) error { return d.SetProp(ctx, d.propOn.siid, d.propOn.piid, true) } func (d *plugDevice) TurnOff(ctx context.Context) error { return d.SetProp(ctx, d.propOn.siid, d.propOn.piid, false) } func (d *plugDevice) IsOn(ctx context.Context) (bool, error) { prop, err := d.GetProp(ctx, d.propOn.siid, d.propOn.piid) if err != nil { return false, err } b, _ := prop.Value.(bool) return b, nil } func (d *plugDevice) OnPropsChanged(handler func(on bool)) (string, error) { return d.SubProp(d.propOn.siid, d.propOn.piid, func(did string, prop *xiaomi.PropertyValue) { if b, ok := prop.Value.(bool); ok { d.propsCache.On = b handler(b) } }) } func (d *plugDevice) GetProps() PlugProps { return d.propsCache } func (d *plugDevice) FetchProps(ctx context.Context) (PlugProps, error) { props, err := d.client.GetProps(ctx, []xiaomi.PropKey{ {DID: d.info.DID, SIID: d.propOn.siid, PIID: d.propOn.piid}, }) if err != nil { return d.propsCache, err } for _, p := range props { if p.SIID == d.propOn.siid && p.PIID == d.propOn.piid { d.propsCache.On, _ = p.Value.(bool) } } return d.propsCache, nil }