diff --git a/samples/hcsr501.go b/samples/hcsr501.go new file mode 100644 index 0000000..89e0d00 --- /dev/null +++ b/samples/hcsr501.go @@ -0,0 +1,41 @@ +// +build ignore + +package main + +import ( + "flag" + "log" + "time" + + "github.com/kidoman/embd" + + _ "github.com/kidoman/embd/host/chip" + "github.com/kidoman/embd/sensor/hcsr501" +) + +func main() { + flag.Parse() + + if err := embd.InitGPIO(); err != nil { + panic(err) + } + defer embd.CloseGPIO() + + trig, err := embd.NewDigitalPin(132) + if err != nil { + panic(err) + } + defer trig.Close() + + pir := hcsr501.New(trig) + + for { + time.Sleep(3 * time.Second) + p, err := pir.Detect() + if err != nil { + log.Printf("error %v", err) + continue + } + log.Printf("PIR Detect %v", p) + } +} diff --git a/sensor/hcsr501/hcsr501.go b/sensor/hcsr501/hcsr501.go new file mode 100644 index 0000000..4da90ac --- /dev/null +++ b/sensor/hcsr501/hcsr501.go @@ -0,0 +1,77 @@ +// Package hcsr501 allows interfacing with the HC-SR501 PIR Sensor. +package hcsr501 + +import ( + "errors" + "sync" + "time" + + "github.com/kidoman/embd" +) + +// HCSR501 represents a HCSR501 ultrasonic range finder. +type HCSR501 struct { + TriggerPin embd.DigitalPin + initialized bool + ready bool // Allows the sensor time to settle in. + mu sync.RWMutex +} + +// New creates a new HCSR501 interface. +func New(triggerPin embd.DigitalPin) *HCSR501 { + return &HCSR501{TriggerPin: triggerPin} +} + +// setup initializes the GPIO and sensor. +func (d *HCSR501) setup() error { + d.mu.RLock() + if d.initialized { + d.mu.RUnlock() + return nil + } + d.mu.RUnlock() + + d.mu.Lock() + defer d.mu.Unlock() + + if err := d.TriggerPin.SetDirection(embd.In); err != nil { + return err + } + + // Wait 60 sec for sensor to settle down. + time.AfterFunc(60*time.Second, func() { + d.ready = true + }) + d.initialized = true + + return nil +} + +// Detect returns true if motion was detected. +func (d *HCSR501) Detect() (bool, error) { + if err := d.setup(); err != nil { + return false, err + } + + if !d.ready { + return false, errors.New("Sensor not ready") + } + + // Check 3 times to be sure. + for i := 0; i < 3; i++ { + v, err := d.TriggerPin.Read() + if err != nil { + return false, err + } + if v == embd.Low { + return false, nil + } + time.Sleep(10 * time.Millisecond) + } + return true, nil +} + +// Close. +func (d *HCSR501) Close() error { + return d.TriggerPin.SetDirection(embd.Out) +}