package devices import ( "context" "fmt" "xiaomihome/xiaomi" ) // OccupancySensor 人在传感器读取接口(只读)。 type OccupancySensor interface { Device // IsOccupied 是否有人。 IsOccupied(ctx context.Context) (bool, error) // GetIlluminance 环境光照度(lux),部分传感器支持。 GetIlluminance(ctx context.Context) (float64, error) } // NewOccupancySensor 创建人在传感器。失败返回错误(含无 SPEC / 无相关属性)。 func NewOccupancySensor(client *xiaomi.Client, info *xiaomi.DeviceInfo) (OccupancySensor, error) { if info == nil { return nil, xiaomi.ErrDeviceNotFound } miotDev := client.GetMIoTDevice(info.DID) if miotDev == nil { return nil, fmt.Errorf("%w: device not initialized", xiaomi.ErrDeviceNotFound) } spec := miotDev.SpecInstance() if spec == nil { return nil, fmt.Errorf("%w: device has no SPEC information", xiaomi.ErrNotSupported) } d := &occupancyDevice{ BaseDevice: BaseDevice{client: client, info: info}, } for _, svc := range spec.Services { for _, prop := range svc.Properties { switch propertyShortName(prop.Type) { case "occupancy": if !d.propOccupancy.valid { d.propOccupancy = siidPiid{svc.IID, prop.PIID, true} } case "illumination": if !d.propIlluminance.valid { d.propIlluminance = siidPiid{svc.IID, prop.PIID, true} } } } } if !d.propOccupancy.valid { return nil, fmt.Errorf("%w: no occupancy property in SPEC", xiaomi.ErrNotSupported) } return d, nil } type occupancyDevice struct { BaseDevice propOccupancy siidPiid propIlluminance siidPiid } func (d *occupancyDevice) IsOccupied(ctx context.Context) (bool, error) { prop, err := d.GetProp(ctx, d.propOccupancy.siid, d.propOccupancy.piid) if err != nil { return false, err } if b, ok := prop.Value.(bool); ok { return b, nil } return false, nil } func (d *occupancyDevice) GetIlluminance(ctx context.Context) (float64, error) { if !d.propIlluminance.valid { return 0, xiaomi.ErrNotSupported } prop, err := d.GetProp(ctx, d.propIlluminance.siid, d.propIlluminance.piid) if err != nil { return 0, err } return toFloat(prop.Value), nil }