mirror of
https://github.com/hybridgroup/gobot.git
synced 2025-04-29 13:49:14 +08:00
115 lines
2.5 KiB
Go
115 lines
2.5 KiB
Go
package gpio
|
|
|
|
import (
|
|
"time"
|
|
|
|
"gobot.io/x/gobot/v2"
|
|
)
|
|
|
|
// PIRMotionDriver represents a digital Proximity Infra Red (PIR) motion detecter
|
|
type PIRMotionDriver struct {
|
|
*Driver
|
|
gobot.Eventer
|
|
pin string
|
|
active bool
|
|
halt chan bool
|
|
interval time.Duration
|
|
}
|
|
|
|
// NewPIRMotionDriver returns a new PIRMotionDriver with a polling interval of
|
|
// 10 Milliseconds given a DigitalReader and pin.
|
|
//
|
|
// Optionally accepts:
|
|
//
|
|
// time.Duration: Interval at which the PIRMotionDriver is polled for new information
|
|
func NewPIRMotionDriver(a DigitalReader, pin string, v ...time.Duration) *PIRMotionDriver {
|
|
//nolint:forcetypeassert // no error return value, so there is no better way
|
|
d := &PIRMotionDriver{
|
|
Driver: NewDriver(a.(gobot.Connection), "PIRMotion"),
|
|
Eventer: gobot.NewEventer(),
|
|
pin: pin,
|
|
active: false,
|
|
interval: 10 * time.Millisecond,
|
|
halt: make(chan bool),
|
|
}
|
|
d.afterStart = d.initialize
|
|
d.beforeHalt = d.shutdown
|
|
|
|
if len(v) > 0 {
|
|
d.interval = v[0]
|
|
}
|
|
|
|
d.AddEvent(MotionDetected)
|
|
d.AddEvent(MotionStopped)
|
|
d.AddEvent(Error)
|
|
|
|
return d
|
|
}
|
|
|
|
// Pin returns the PIRMotionDriver pin
|
|
func (d *PIRMotionDriver) Pin() string { return d.pin }
|
|
|
|
// Active gets the current state
|
|
func (d *PIRMotionDriver) Active() bool {
|
|
// ensure that read and write can not interfere
|
|
d.mutex.Lock()
|
|
defer d.mutex.Unlock()
|
|
|
|
return d.active
|
|
}
|
|
|
|
// initialize the PIRMotionDriver and polls the state of the sensor at the given interval.
|
|
//
|
|
// Emits the Events:
|
|
//
|
|
// MotionDetected - On motion detected
|
|
// MotionStopped int - On motion stopped
|
|
// Error error - On button error
|
|
//
|
|
// The PIRMotionDriver will send the MotionDetected event over and over,
|
|
// just as long as motion is still being detected.
|
|
// It will only send the MotionStopped event once, however, until
|
|
// motion starts being detected again
|
|
func (d *PIRMotionDriver) initialize() error {
|
|
go func() {
|
|
for {
|
|
newValue, err := d.connection.(DigitalReader).DigitalRead(d.Pin())
|
|
if err != nil {
|
|
d.Publish(Error, err)
|
|
}
|
|
d.update(newValue)
|
|
select {
|
|
case <-time.After(d.interval):
|
|
case <-d.halt:
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
return nil
|
|
}
|
|
|
|
// shutdown stops polling
|
|
func (d *PIRMotionDriver) shutdown() error {
|
|
d.halt <- true
|
|
return nil
|
|
}
|
|
|
|
func (d *PIRMotionDriver) update(newValue int) {
|
|
// ensure that read and write can not interfere
|
|
d.mutex.Lock()
|
|
defer d.mutex.Unlock()
|
|
|
|
switch newValue {
|
|
case 1:
|
|
if !d.active {
|
|
d.active = true
|
|
d.Publish(MotionDetected, newValue)
|
|
}
|
|
case 0:
|
|
if d.active {
|
|
d.active = false
|
|
d.Publish(MotionStopped, newValue)
|
|
}
|
|
}
|
|
}
|