package devices import ( "context" "xiaomihome/xiaomi" ) // Fan 风扇统一控制接口 type Fan interface { Device TurnOn(ctx context.Context) error TurnOff(ctx context.Context) error IsOn(ctx context.Context) (bool, error) SetFanLevel(ctx context.Context, level int) error // 0=off, 1-4 档位 GetFanLevel(ctx context.Context) (int, error) SetOscillation(ctx context.Context, on bool) error IsOscillating(ctx context.Context) (bool, error) SetNaturalWind(ctx context.Context, on bool) error IsNaturalWind(ctx context.Context) (bool, error) } type fanDevice struct { BaseDevice propOn siidPiid // "on" propFanLevel siidPiid // "fan-level" propOscillation siidPiid // "horizontal-swing" or "oscillation" propNaturalWind siidPiid // "mode" (natural wind mode) } // NewFan creates a Fan control for the given device. func NewFan(client *xiaomi.Client, info *xiaomi.DeviceInfo) (Fan, error) { d := &fanDevice{ BaseDevice: NewBaseDevice(client, info), } resolver := d.getSpecResolver() if resolver == nil { return nil, xiaomi.ErrNoSPEC } siid, piid, ok := resolver.find("on") if !ok { return nil, xiaomi.ErrNotSupported } d.propOn = siidPiid{siid, piid, true} if s, p, ok := resolver.find("fan-level"); ok { d.propFanLevel = siidPiid{s, p, true} } if s, p, ok := resolver.find("horizontal-swing"); ok { d.propOscillation = siidPiid{s, p, true} } if s, p, ok := resolver.find("mode"); ok { d.propNaturalWind = siidPiid{s, p, true} } return d, nil } func (d *fanDevice) TurnOn(ctx context.Context) error { if !d.propOn.valid { return xiaomi.ErrNotSupported } return d.SetProp(ctx, d.propOn.siid, d.propOn.piid, true) } func (d *fanDevice) TurnOff(ctx context.Context) error { if !d.propOn.valid { return xiaomi.ErrNotSupported } return d.SetProp(ctx, d.propOn.siid, d.propOn.piid, false) } func (d *fanDevice) IsOn(ctx context.Context) (bool, error) { if !d.propOn.valid { return false, xiaomi.ErrNotSupported } prop, err := d.GetProp(ctx, d.propOn.siid, d.propOn.piid) if err != nil { return false, err } if b, ok := prop.Value.(bool); ok { return b, nil } return false, nil } func (d *fanDevice) SetFanLevel(ctx context.Context, level int) error { if !d.propFanLevel.valid { return xiaomi.ErrNotSupported } return d.SetProp(ctx, d.propFanLevel.siid, d.propFanLevel.piid, level) } func (d *fanDevice) GetFanLevel(ctx context.Context) (int, error) { if !d.propFanLevel.valid { return 0, xiaomi.ErrNotSupported } prop, err := d.GetProp(ctx, d.propFanLevel.siid, d.propFanLevel.piid) if err != nil { return 0, err } return toInt(prop.Value), nil } func (d *fanDevice) SetOscillation(ctx context.Context, on bool) error { if !d.propOscillation.valid { return xiaomi.ErrNotSupported } return d.SetProp(ctx, d.propOscillation.siid, d.propOscillation.piid, on) } func (d *fanDevice) IsOscillating(ctx context.Context) (bool, error) { if !d.propOscillation.valid { return false, xiaomi.ErrNotSupported } prop, err := d.GetProp(ctx, d.propOscillation.siid, d.propOscillation.piid) if err != nil { return false, err } if b, ok := prop.Value.(bool); ok { return b, nil } return false, nil } func (d *fanDevice) SetNaturalWind(ctx context.Context, on bool) error { if !d.propNaturalWind.valid { return xiaomi.ErrNotSupported } mode := 0 // normal if on { mode = 1 // natural wind } return d.SetProp(ctx, d.propNaturalWind.siid, d.propNaturalWind.piid, mode) } func (d *fanDevice) IsNaturalWind(ctx context.Context) (bool, error) { if !d.propNaturalWind.valid { return false, xiaomi.ErrNotSupported } prop, err := d.GetProp(ctx, d.propNaturalWind.siid, d.propNaturalWind.piid) if err != nil { return false, err } return toInt(prop.Value) == 1, nil }