Files
xiaomihome/xiaomi/devices/humidifier.go
T
4566704 8ffc9e4e44 refactor: 重构 token 管理,新增 NATS adapter 和多示例
按照 TOKEN_REFACTOR.md / FIX_CONFIG.md 方案重构核心层:
- miot: Init() 优先读 storage token,新增 RefreshAuthInfo() 和刷新回调
- xiaomi: Config 改用 AuthInfo 结构体(含 UUID/UID/DataDir/OnTokenRefreshed)
- xiaomi: NewClient(ctx, Config) 新签名,新增 RefreshToken(),后台自动刷新
- xiaomi/devices: 设备控制接口重构
- 新增示例 12_ac_subscribe,其余示例适配新 Config
2026-06-30 12:16:49 +08:00

108 lines
4.2 KiB
Go

package devices
import (
"context"
"xiaomihome/xiaomi"
)
// Humidifier 加湿器/除湿机统一控制接口
type Humidifier interface {
Device
TurnOn(ctx context.Context) error
TurnOff(ctx context.Context) error
IsOn(ctx context.Context) (bool, error)
SetTargetHumidity(ctx context.Context, pct int) error
GetTargetHumidity(ctx context.Context) (int, error)
SetFanLevel(ctx context.Context, level int) error
GetFanLevel(ctx context.Context) (int, error)
OnStateChanged(handler func(state HumidifierState, changed string)) (string, error)
}
// HumidifierState 加湿器状态(MQTT 缓存)
type HumidifierState struct {
On bool `json:"on"`
TargetHumidity int `json:"targetHumidity"`
FanLevel int `json:"fanLevel"`
}
type humidifierDevice struct {
BaseDevice
propOn siidPiid
propTargetHumidity siidPiid
propFanLevel siidPiid
stateCache HumidifierState
}
func NewHumidifier(client *xiaomi.Client, info *xiaomi.DeviceInfo) (Humidifier, error) {
d := &humidifierDevice{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("target-humidity"); ok { d.propTargetHumidity = siidPiid{s, p, true} }
if s, p, ok := resolver.find("fan-level"); ok { d.propFanLevel = siidPiid{s, p, true} }
return d, nil
}
func (d *humidifierDevice) 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 *humidifierDevice) 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 *humidifierDevice) 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 *humidifierDevice) SetTargetHumidity(ctx context.Context, pct int) error {
if !d.propTargetHumidity.valid { return xiaomi.ErrNotSupported }
return d.SetProp(ctx, d.propTargetHumidity.siid, d.propTargetHumidity.piid, pct)
}
func (d *humidifierDevice) GetTargetHumidity(ctx context.Context) (int, error) {
if !d.propTargetHumidity.valid { return 0, xiaomi.ErrNotSupported }
prop, err := d.GetProp(ctx, d.propTargetHumidity.siid, d.propTargetHumidity.piid)
if err != nil { return 0, err }
return toInt(prop.Value), nil
}
func (d *humidifierDevice) 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 *humidifierDevice) 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 *humidifierDevice) OnStateChanged(handler func(state HumidifierState, changed string)) (string, error) {
type field struct{ siid, piid int; name string; fill func(*HumidifierState, interface{}) }
var fields []field
if d.propOn.valid {
fields = append(fields, field{d.propOn.siid, d.propOn.piid, "on", func(s *HumidifierState, v interface{}) { s.On, _ = v.(bool) }})
}
if d.propTargetHumidity.valid {
fields = append(fields, field{d.propTargetHumidity.siid, d.propTargetHumidity.piid, "target-humidity", func(s *HumidifierState, v interface{}) { s.TargetHumidity = toInt(v) }})
}
if d.propFanLevel.valid {
fields = append(fields, field{d.propFanLevel.siid, d.propFanLevel.piid, "fan-level", func(s *HumidifierState, v interface{}) { s.FanLevel = toInt(v) }})
}
if len(fields) == 0 { return "", xiaomi.ErrNotSupported }
return d.SubProp(0, 0, func(did string, prop *xiaomi.PropertyValue) {
for _, f := range fields {
if f.siid == prop.SIID && f.piid == prop.PIID {
f.fill(&d.stateCache, prop.Value)
handler(d.stateCache, f.name)
return
}
}
})
}