package devices import ( "context" "xiaomihome/xiaomi" ) // Thermostat 温控器/电热毯统一控制接口 type Thermostat interface { Device TurnOn(ctx context.Context) error TurnOff(ctx context.Context) error IsOn(ctx context.Context) (bool, error) SetTargetTemp(ctx context.Context, celsius float64) error GetTargetTemp(ctx context.Context) (float64, error) GetCurrentTemp(ctx context.Context) (float64, error) SetHeating(ctx context.Context, on bool) error IsHeating(ctx context.Context) (bool, error) } type thermostatDevice struct { BaseDevice propOn siidPiid // "on" propTargetTemp siidPiid // "target-temperature" propCurrentTemp siidPiid // "temperature" propHeating siidPiid // "heating" or "mode" } // NewThermostat creates a Thermostat control for the given device. func NewThermostat(client *xiaomi.Client, info *xiaomi.DeviceInfo) (Thermostat, error) { d := &thermostatDevice{ 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-temperature"); ok { d.propTargetTemp = siidPiid{s, p, true} } if s, p, ok := resolver.find("temperature"); ok { d.propCurrentTemp = siidPiid{s, p, true} } if s, p, ok := resolver.find("heating"); ok { d.propHeating = siidPiid{s, p, true} } else if s, p, ok := resolver.find("heater"); ok { d.propHeating = siidPiid{s, p, true} } return d, nil } func (d *thermostatDevice) 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 *thermostatDevice) 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 *thermostatDevice) 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 *thermostatDevice) SetTargetTemp(ctx context.Context, celsius float64) error { if !d.propTargetTemp.valid { return xiaomi.ErrNotSupported } return d.SetProp(ctx, d.propTargetTemp.siid, d.propTargetTemp.piid, celsius) } func (d *thermostatDevice) GetTargetTemp(ctx context.Context) (float64, error) { if !d.propTargetTemp.valid { return 0, xiaomi.ErrNotSupported } prop, err := d.GetProp(ctx, d.propTargetTemp.siid, d.propTargetTemp.piid) if err != nil { return 0, err } return toFloat(prop.Value), nil } func (d *thermostatDevice) GetCurrentTemp(ctx context.Context) (float64, error) { if !d.propCurrentTemp.valid { return 0, xiaomi.ErrNotSupported } prop, err := d.GetProp(ctx, d.propCurrentTemp.siid, d.propCurrentTemp.piid) if err != nil { return 0, err } return toFloat(prop.Value), nil } func (d *thermostatDevice) SetHeating(ctx context.Context, on bool) error { if !d.propHeating.valid { return xiaomi.ErrNotSupported } return d.SetProp(ctx, d.propHeating.siid, d.propHeating.piid, on) } func (d *thermostatDevice) IsHeating(ctx context.Context) (bool, error) { if !d.propHeating.valid { return false, xiaomi.ErrNotSupported } prop, err := d.GetProp(ctx, d.propHeating.siid, d.propHeating.piid) if err != nil { return false, err } if b, ok := prop.Value.(bool); ok { return b, nil } return false, nil }