- 改动:go.mod module 声明与全部内部导入路径补全为完整域名路径,README 同步 - 原因:裸模块名无法被 go get 解析,发版前必须修正为 GOPRIVATE 可拉取路径
103 lines
2.5 KiB
Go
103 lines
2.5 KiB
Go
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
|
|
}
|