#!/usr/bin/env python import signal import socket import time import string import sys import RPi.GPIO as GPIO import time import math from array import * import logging import os GPIO_SWITCH = 15 GPIO_PIR = 18 GPIO_SOUNDER = 22 GPIO_LED = 12 alarm_on = False intruder_alert = False sleep_time = 60.0 sig_count = 0 def SignalHandler(signal, frame): global fsm_input global keep_spinning if fsm_input == INPUT_NONE: keep_spinning = False def switch_callback(channel): global fsm_input logger.info("Switch callback") fsm_input = INPUT_SWITCH os.kill(os.getpid(), signal.SIGINT) def PIR_callback(channel): global fsm_input logger.info("PIR callback") fsm_input = INPUT_PIR os.kill(os.getpid(), signal.SIGINT) #------------------------------------------------------------------------------------------- # Create a base level logger #------------------------------------------------------------------------------------------- logger = logging.getLogger('drone logger') logger.setLevel(logging.INFO) #------------------------------------------------------------------------------------------- # Create file and console logger handlers #------------------------------------------------------------------------------------------- file_handler = logging.FileHandler('drone.log', 'w') file_handler.setLevel(logging.WARNING) console_handler = logging.StreamHandler() console_handler.setLevel(logging.DEBUG) #------------------------------------------------------------------------------------------- # Create a formatter and add it to both handlers #------------------------------------------------------------------------------------------- # create formatter and add it to the handlers formatter = logging.Formatter('[%(levelname)s] (%(threadName)-10s) %(message)s') console_handler.setFormatter(formatter) file_handler.setFormatter(formatter) #------------------------------------------------------------------------------------------- # Create a formatter and add it to both handlers #------------------------------------------------------------------------------------------- logger.addHandler(console_handler) logger.addHandler(file_handler) signal.signal(signal.SIGINT, SignalHandler) GPIO.setmode(GPIO.BOARD) GPIO.setup(GPIO_SWITCH, GPIO.IN, pull_up_down = GPIO.PUD_DOWN) GPIO.setup(GPIO_PIR, GPIO.IN, pull_up_down = GPIO.PUD_DOWN) GPIO.setup(GPIO_SOUNDER, GPIO.OUT) GPIO.output(GPIO_SOUNDER, GPIO.LOW) GPIO.setup(GPIO_LED, GPIO.OUT) GPIO.output(GPIO_LED, GPIO.LOW) #------------------------------------------------------------------------------------------- # OK, all set up, setup the switch interrupt #------------------------------------------------------------------------------------------- GPIO.add_event_detect(GPIO_SWITCH, GPIO.RISING, callback = switch_callback, bouncetime = 200) keep_spinning = True arming_period = 0.0 INPUT_NONE = 0 INPUT_SWITCH = 1 INPUT_PIR = 2 INPUT_TIMER = 3 fsm_input = INPUT_NONE STATE_OFF = 0 STATE_ARMING = 1 STATE_ARMED = 2 STATE_INTRUDER = 3 fsm_state = STATE_OFF ACT_NONE = 0 ACT_ARM_ALARM = 1 ACT_ENABLE_PIR = 2 ACT_INTRUDER_ALERT = 3 ACT_DISARM_ALARM = 4 fsm_action = 0 #------------------------------------------------------------------------------------------- # Sleep until the Alarm is turned on #------------------------------------------------------------------------------------------- while keep_spinning: time.sleep(sleep_time) logger.info("Who woke me up?") #----------------------------------------------------------------------------------- # By implementing this as an FSM, using signal handlers from all event callback to wake # the main thread, then this works around the switch debounce delay #----------------------------------------------------------------------------------- if fsm_input == INPUT_SWITCH: fsm_input = INPUT_NONE if fsm_state == STATE_OFF: fsm_state = STATE_ARMING fsm_action = ACT_ARM_ALARM start_arming = time.time() else: fsm_state = STATE_OFF fsm_action = ACT_DISARM_ALARM if fsm_input == INPUT_PIR: fsm_input = INPUT_NONE if fsm_state == STATE_ARMED or fsm_state == STATE_INTRUDER: fsm_state = STATE_INTRUDER fsm_action = ACT_INTRUDER_ALERT if fsm_input == INPUT_TIMER: fsm_input = INPUT_NONE if fsm_state == STATE_ARMING: fsm_state = STATE_ARMED fsm_action = ACT_ENABLE_PIR #----------------------------------------------------------------------------------- # Now act upon the results of the FSM processing #----------------------------------------------------------------------------------- if fsm_action == ACT_ARM_ALARM: # fsm_action = ACT_NONE #------------------------------------------------------------------- # Set the LED on, beep for 30s, then turn the LED off #------------------------------------------------------------------- logger.info("Arming alarm") GPIO.output(GPIO_LED, GPIO.HIGH) GPIO.output(GPIO_SOUNDER, not GPIO.input(GPIO_SOUNDER)) time.sleep(0.01) GPIO.output(GPIO_SOUNDER, not GPIO.input(GPIO_SOUNDER)) sleep_time = 0.49 if time.time() - start_arming > 30.0: GPIO.output(GPIO_LED, GPIO.LOW) fsm_input = INPUT_TIMER if fsm_action == ACT_ENABLE_PIR: #------------------------------------------------------------------- # The alarm has just been turned on, enable the PIR #------------------------------------------------------------------- fsm_action = ACT_NONE logger.info("Enabling PIR") GPIO.add_event_detect(GPIO_PIR, GPIO.RISING, callback = PIR_callback) GPIO.output(GPIO_LED, GPIO.HIGH) time.sleep(0.1) GPIO.output(GPIO_LED, GPIO.LOW) sleep_time = 60.0 if fsm_action == ACT_INTRUDER_ALERT: #----------------------------------------------------------------------------------- # Intruder alert, beep annoyingly for 5 minutes; when hub exists, contact to trigger throughout the house #----------------------------------------------------------------------------------- logger.info("!!!!!!!!!!!!Intruder Alert!!!!!!!!!!!!") GPIO.output(GPIO_SOUNDER, not GPIO.input(GPIO_SOUNDER)) GPIO.remove_event_detect(GPIO_PIR) sleep_time = 1.0 fsm_input = INPUT_PIR if fsm_action == ACT_DISARM_ALARM: #--------------------------------------------------------------------------- # Turn off LED, sounder, PIR #--------------------------------------------------------------------------- fsm_action = ACT_NONE logger.info("Disarm alarm") GPIO.output(GPIO_SOUNDER, GPIO.LOW) GPIO.output(GPIO_LED, GPIO.LOW) GPIO.remove_event_detect(GPIO_PIR) sleep_time = 60.0 GPIO.cleanup()