def __init__(self): self.__xml = XML_Object () # self.__JOB_SCHED_IP = self.__xml.get_job_scheduler_ip () # self.__JOB_SCHED_PORT = self.__xml.get_job_scheduler_port () # self.__JOB_SCHED_RECV_ADDR = (self.__JOB_SCHED_IP, self.__JOB_SCHED_PORT) #-------------------------------------------------------------------------# #----------------------------- SCHEDULER INIT ----------------------------# #-------------------------------------------------------------------------# self.__sched = BackgroundScheduler() self.__sched.start() # start the scheduler log.print_high ('Scheduler started') #-------------------------------------------------------------------------# #----------------------------- INSTAPUSH INIT ----------------------------# #-------------------------------------------------------------------------# self.__INSTAPUSH_NOTIF_IP = self.__xml.get_instapush_notif_ip () self.__INSTAPUSH_NOTIF_PORT = self.__xml.get_instapush_notif_port () self.__INSTAPUSH_NOTIF_ADDR = (self.__INSTAPUSH_NOTIF_IP, self.__INSTAPUSH_NOTIF_PORT) self.__udp_send_sock = socket(AF_INET, SOCK_DGRAM) self.__min_gap_between_two_instapush_notif = self.__xml.min_gap_between_two_instapush_notif () # Record the timestamp when the last instapush notification was sent self.__last_instapush_notif_sent_at = datetime.datetime.now () self.__is_stream_job_running = False self.__outside_PIR_interrupt_count = 0 self.__instapush_notif_timeout_job = self.__sched.add_job(self.send_instapush_notif, 'interval', seconds = 5, args=['Dummy message']) self.__instapush_notif_timeout_job.remove () #-------------------------------------------------------------------------# #--------------------------- PITFT SCREEN INIT ---------------------------# #-------------------------------------------------------------------------# # Create TFT display object self.__pitft = PiTFT_Screen () log.print_high ('Created TFT display object') # Start Framebuffer copy daemon self.__pitft.start_fbcp_process() self.__cam = Cam_Object () log.print_high ('Created camera object') # Create a dummy job and cancel it self.__stream_job = self.__sched.add_job(self.stop_streaming_cb, 'interval', seconds = 5) self.__stream_job.remove () log.print_high ('Scheduler init done') #-------------------------------------------------------------------------# #---------------------------- INTERRUPTS INIT ----------------------------# #-------------------------------------------------------------------------# self.__last_inside_pir_interrupt_triggered_at = datetime.datetime.now () self.__last_outside_pir_interrupt_triggered_at = datetime.datetime.now () self.__last_door_switch_interrupt_triggered_at = datetime.datetime.now ()
class Sched_Obj: #=========================================================================# #-------------------------------- INIT -----------------------------------# #=========================================================================# def __init__(self): self.__xml = XML_Object () # self.__JOB_SCHED_IP = self.__xml.get_job_scheduler_ip () # self.__JOB_SCHED_PORT = self.__xml.get_job_scheduler_port () # self.__JOB_SCHED_RECV_ADDR = (self.__JOB_SCHED_IP, self.__JOB_SCHED_PORT) #-------------------------------------------------------------------------# #----------------------------- SCHEDULER INIT ----------------------------# #-------------------------------------------------------------------------# self.__sched = BackgroundScheduler() self.__sched.start() # start the scheduler log.print_high ('Scheduler started') #-------------------------------------------------------------------------# #----------------------------- INSTAPUSH INIT ----------------------------# #-------------------------------------------------------------------------# self.__INSTAPUSH_NOTIF_IP = self.__xml.get_instapush_notif_ip () self.__INSTAPUSH_NOTIF_PORT = self.__xml.get_instapush_notif_port () self.__INSTAPUSH_NOTIF_ADDR = (self.__INSTAPUSH_NOTIF_IP, self.__INSTAPUSH_NOTIF_PORT) self.__udp_send_sock = socket(AF_INET, SOCK_DGRAM) self.__min_gap_between_two_instapush_notif = self.__xml.min_gap_between_two_instapush_notif () # Record the timestamp when the last instapush notification was sent self.__last_instapush_notif_sent_at = datetime.datetime.now () self.__is_stream_job_running = False self.__outside_PIR_interrupt_count = 0 self.__instapush_notif_timeout_job = self.__sched.add_job(self.send_instapush_notif, 'interval', seconds = 5, args=['Dummy message']) self.__instapush_notif_timeout_job.remove () #-------------------------------------------------------------------------# #--------------------------- PITFT SCREEN INIT ---------------------------# #-------------------------------------------------------------------------# # Create TFT display object self.__pitft = PiTFT_Screen () log.print_high ('Created TFT display object') # Start Framebuffer copy daemon self.__pitft.start_fbcp_process() self.__cam = Cam_Object () log.print_high ('Created camera object') # Create a dummy job and cancel it self.__stream_job = self.__sched.add_job(self.stop_streaming_cb, 'interval', seconds = 5) self.__stream_job.remove () log.print_high ('Scheduler init done') #-------------------------------------------------------------------------# #---------------------------- INTERRUPTS INIT ----------------------------# #-------------------------------------------------------------------------# self.__last_inside_pir_interrupt_triggered_at = datetime.datetime.now () self.__last_outside_pir_interrupt_triggered_at = datetime.datetime.now () self.__last_door_switch_interrupt_triggered_at = datetime.datetime.now () #=========================================================================# #------------------------------ INIT END ---------------------------------# #=========================================================================# #-------------------------------------------------------------------------# #-------------------- INTERRUPT TRIGGERED FUNCTIONS ---------------------# #-------------------------------------------------------------------------# def update_inside_pir_interrupt_timestamp (self): self.__last_inside_pir_interrupt_triggered_at = datetime.datetime.now () def how_long_ago_was_last_inside_pir_interrupt_triggered (self): return get_elapsed_seconds_since (self.__last_inside_pir_interrupt_triggered_at) #-------------------------------------------------------------------------# def update_outside_pir_interrupt_timestamp (self): self.__last_outside_pir_interrupt_triggered_at = datetime.datetime.now () def how_long_ago_was_last_inside_pir_interrupt_triggered (self): return get_elapsed_seconds_since (self.__last_outside_pir_interrupt_triggered_at) #-------------------------------------------------------------------------# def update_door_switch_interrupt_timestamp (self): self.__last_door_switch_interrupt_triggered_at = datetime.datetime.now () def how_long_ago_was_last_inside_pir_interrupt_triggered (self): return get_elapsed_seconds_since (self.__last_door_switch_interrupt_triggered_at) #-------------------------------------------------------------------------# #---------------------- INSTAPUSH NOTIFICATION HANDLER -------------------# #-------------------------------------------------------------------------# def how_long_ago_was_last_instapush_notif_sent (self): return get_elapsed_seconds_since (self.__last_instapush_notif_sent_at) #-------------------------------------------------------------------------# # Send an instapush notification if we get more than # 2 interrupts (reconfigurable) during the timout (also reconfigurable) # To avoid flooding notifications, allow a minimum gap between two # notifications. Currently set to 5 minutes (reconfigurable) def send_instapush_notif (self, notif_message): # Remove the interval job self.__instapush_notif_timeout_job.remove () log.print_high ('send_instapush_notif triggered') # Check the interrupt count during the timeout. If greater than the # threshold, send a notification. # Also check when the last notification was sent. if ( (self.__outside_PIR_interrupt_count > self.__xml.get_instapush_notif_interrupt_count()) and (self.how_long_ago_was_last_instapush_notif_sent () > self.__min_gap_between_two_instapush_notif) ): log.print_high ('Will send a notif now') self.__udp_send_sock.sendto (notif_message, self.__INSTAPUSH_NOTIF_ADDR) self.__last_instapush_notif_sent_at = datetime.datetime.now () else: log.print_high ('No notif. Last notif sent ' + str (self.how_long_ago_was_last_instapush_notif_sent ()) + 's ago. Interrupt count = ' + str (self.__outside_PIR_interrupt_count)) # Reset the counter for the current cycle self.__outside_PIR_interrupt_count = 0 return #-------------------------------------------------------------------------# # Count the number of interrupts in 20 seconds (reconfigurable) to ensure a # person is standing outside the door def schedule_instapush_notif_timeout (self, instapush_notif_timeout = 20): instapush_notif_timeout = self.__xml.get_instapush_notif_timeout () self.__instapush_notif_timeout_job = self.__sched.add_job(self.send_instapush_notif, 'interval', seconds=instapush_notif_timeout, args=['Someone at the door']) log.print_high ('Scheduled instapush_notif_timeout for ' + str (instapush_notif_timeout) + 's') return #-------------------------------------------------------------------------# def check_if_door_opened_from_outside_and_send_notif (self): # Check if someone was recently inside the house, behind the door if (self.how_long_ago_was_last_inside_pir_interrupt_triggered () > xml.inside_home_presence_timeout()): # If no one was inside the house and door was opened, send a notification self.send_instapush_notif ('Door opened') #-------------------------------------------------------------------------# # Increment interrupt count and start a timer def increment_outside_PIR_interrupt_count (self): if (self.__outside_PIR_interrupt_count == 0): self.schedule_instapush_notif_timeout () self.__outside_PIR_interrupt_count = self.__outside_PIR_interrupt_count + 1 log.print_high ('# of interrupts = ' + str (self.__outside_PIR_interrupt_count)) return #-------------------------------------------------------------------------# #------------------------------ STREAM HANDLER ---------------------------# #-------------------------------------------------------------------------# # Implemented as a callback function def start_streaming_cb (self): if (not self.__is_stream_job_running): log.print_high ('Starting camera...') if (self.__cam.start_camera ('320x240', '5', 'night')): self.__pitft.Backlight (True) log.print_high ('scheduler: Starting stream_video_to_display...') self.__pitft.stream_video_to_display () else: log.print_high ('scheduler: Camera already on') self.__is_stream_job_running = True return #-------------------------------------------------------------------------# # Turns off camera streaming. # Turns off local display def stop_streaming_cb (self): # First cancel the interval job self.__stream_job.remove () log.print_high ('Stopping stream...') self.__pitft.stop_stream_video_to_display () log.print_high ('Stream stoppped. Turning backlight off...') self.__pitft.Backlight (False) log.print_high ('Backlight off. Stopping camera...') if (self.__cam.stop_camera ()): log.print_high ('scheduler: Camera off') self.__is_stream_job_running = False else: log.print_high ('scheduler: Could not turn off camera') log.print_high ('exiting inside_pir_triggered_callback') return #-------------------------------------------------------------------------# # Default schedule delay is 0 minutes def schedule_start_streaming (self, delay = 0): if (delay == 0): self.start_streaming_cb () return #-------------------------------------------------------------------------# # Default schedule delay is 4 minutes def schedule_stop_streaming (self, seconds_delay = 240): # Blindly cancel the job before scheduling it self.__stream_job.remove () self.__stream_job = self.__sched.add_job(self.stop_streaming_cb, 'interval', seconds = seconds_delay) #self.__stream_job = self.__sched.add_date_job(self.stop_streaming_cb, datetime.datetime.today () + datetime.timedelta (seconds = seconds_delay)) log.print_high ('Will turn off stream after ' + str (seconds_delay) + 's from now') return