diff --git a/s_motion_sensor.go b/s_motion_sensor.go index e028537..ea252e8 100644 --- a/s_motion_sensor.go +++ b/s_motion_sensor.go @@ -1,6 +1,9 @@ package hapz2m import ( + "sync" + "time" + "github.com/brutella/hap/accessory" "github.com/brutella/hap/service" ) @@ -8,6 +11,35 @@ import ( // there isn't a distinction between motion and occupancy sensors in z2m, // but most sensors are PIR, so they are technically motion sensors +func setupDelayedOff(m *ExposeMapping, delay time.Duration) { + // lock makes sure Timer and setFunc aren't stepping over each other + lock := &sync.Mutex{} + + tm := time.AfterFunc(1*time.Minute, func() { + lock.Lock() + defer lock.Unlock() + + m.Characteristic.SetValueRequest( /*motion*/ false, nil) + }) + tm.Stop() + + m.SetCharacteristicValueFunc = func(m *ExposeMapping, newVal any, changed bool) (bool, error) { + lock.Lock() + defer lock.Unlock() + + if newVal == true { // motion detected + tm.Stop() + } else { // hold off transitions to no motion + if changed { + tm.Reset(delay) + } + return false, nil + } + + return true, nil + } +} + func createMotionServices(dev *Device) (byte, []*service.S, []*ExposeMapping, error) { var svcs []*service.S var exposes []*ExposeMapping @@ -23,8 +55,11 @@ func createMotionServices(dev *Device) (byte, []*service.S, []*ExposeMapping, er s := service.NewMotionSensor() + m := NewExposeMapping(&exp, s.MotionDetected.C) + setupDelayedOff(m, 1*time.Minute) + svcs = append(svcs, s.S) - exposes = append(exposes, NewExposeMapping(&exp, s.MotionDetected.C)) + exposes = append(exposes, m) } }