2017-06-18 15:31:02 -04:00
|
|
|
'''
|
|
|
|
IR and magnetic sensors
|
|
|
|
'''
|
2016-12-30 02:51:56 -05:00
|
|
|
import RPi.GPIO as GPIO
|
|
|
|
import logging, time
|
|
|
|
from functools import partial
|
2017-06-10 02:25:22 -04:00
|
|
|
from threading import Timer
|
2016-12-30 02:51:56 -05:00
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
2017-06-13 02:48:56 -04:00
|
|
|
# this importantly controls which sensor events get logged. DEBUG logs
|
|
|
|
# everything, INFO logs only events that occur when state machine in
|
2017-06-18 15:16:42 -04:00
|
|
|
# "sensitive states" (armed, trippedCountdown, tripped)
|
2017-06-13 02:48:56 -04:00
|
|
|
logger.setLevel(logging.INFO)
|
2016-12-30 02:51:56 -05:00
|
|
|
|
|
|
|
# delay GPIO init to avoid false positive during powerup
|
|
|
|
INIT_DELAY = 60
|
|
|
|
|
2017-06-13 02:51:08 -04:00
|
|
|
def _lowPassFilter(pin, targetVal, period=0.001):
|
2017-06-18 15:31:02 -04:00
|
|
|
'''
|
|
|
|
Crude implementation of an LPF for a binary signal. This exists to filter
|
|
|
|
out voltage spikes that are induced by mains current fuctuations.
|
|
|
|
|
|
|
|
Basically uses a timed loop to determine if a pin is changing within a
|
|
|
|
given period. If a change occurs within period, this is considered 'high
|
|
|
|
frequency' and the function returns False. If not, the pin is evaluated with
|
|
|
|
a target value, which returns a boolean result that can be used elsewhere
|
|
|
|
'''
|
2016-12-30 02:51:56 -05:00
|
|
|
divisions = 10
|
|
|
|
sleepTime = period/divisions
|
|
|
|
|
|
|
|
for i in range(0, divisions):
|
|
|
|
time.sleep(sleepTime)
|
|
|
|
if GPIO.input(pin) != targetVal:
|
|
|
|
return False
|
|
|
|
|
|
|
|
return GPIO.input(pin) == targetVal
|
|
|
|
|
2017-06-07 01:42:58 -04:00
|
|
|
def _initGPIO(name, pin, GPIOEvent, callback):
|
2017-06-13 02:49:36 -04:00
|
|
|
logger.debug('starting \"%s\" on pin %s', name, pin)
|
2016-12-30 02:51:56 -05:00
|
|
|
GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
|
|
|
|
GPIO.add_event_detect(pin, GPIOEvent, callback=callback, bouncetime=500)
|
|
|
|
|
2017-06-07 01:42:58 -04:00
|
|
|
def startMotionSensor(pin, location, action):
|
2016-12-30 02:51:56 -05:00
|
|
|
name = 'MotionSensor@' + location
|
|
|
|
|
|
|
|
def trip(channel):
|
2017-06-13 02:51:08 -04:00
|
|
|
if _lowPassFilter(pin, 1):
|
2017-06-13 02:48:56 -04:00
|
|
|
action(location, logger)
|
2016-12-30 02:51:56 -05:00
|
|
|
|
|
|
|
logger.debug('waiting %s for %s to power on', INIT_DELAY, name)
|
2017-06-10 02:25:22 -04:00
|
|
|
t = Timer(INIT_DELAY, partial(_initGPIO, name, pin, GPIO.RISING, trip))
|
|
|
|
t.daemon = True
|
|
|
|
t.start()
|
2016-12-30 02:51:56 -05:00
|
|
|
|
2017-06-13 02:48:56 -04:00
|
|
|
def startDoorSensor(pin, action):
|
2016-12-30 02:51:56 -05:00
|
|
|
def trip(channel):
|
|
|
|
nonlocal closed
|
|
|
|
val = GPIO.input(pin)
|
|
|
|
|
|
|
|
if val != closed:
|
2017-06-13 02:51:08 -04:00
|
|
|
if _lowPassFilter(pin, val):
|
2016-12-30 02:51:56 -05:00
|
|
|
closed = val
|
2017-06-13 02:48:56 -04:00
|
|
|
action(closed, logger)
|
2016-12-30 02:51:56 -05:00
|
|
|
|
2017-06-07 01:42:58 -04:00
|
|
|
_initGPIO('DoorSensor', pin, GPIO.BOTH, trip)
|
2016-12-30 02:51:56 -05:00
|
|
|
closed = GPIO.input(pin)
|