def run(self): service_list = [] try: log.info(""" ---------------------------- --- Picammory Starting --- ---------------------------- """) os.chdir(os.path.expanduser('~/picammory/picammory/')) log.info("os.getcwd() = '%s'", os.getcwd()) #--- # for gpio_pin in (5, 23, 24, 25): # subprocess.call(['/usr/local/bin/gpio', 'export', str(gpio_pin), 'out']) # wiringpi2.wiringPiSetupSys() #--- config.config_load('picammory.ini') #--- # LEDProcessor.start() # service_list.append(LEDProcessor) # # LEDProcessor.blue(True) #--- MailService.start() service_list.append(MailService) MailService.send_message('Picammory', 'Picammory Server Starting') # LEDProcessor.green(True) #--- FtpUploader.start() service_list.append(FtpUploader) # LEDProcessor.red(True) #--- log.info("Start Cam Processor") self.cam_processor = CamProcessor(os.path.expanduser('~/picammory_storage/')) service_list.append(self.cam_processor) # LEDProcessor.blue(False) #--- # LEDProcessor.green(False) # LEDProcessor.red(False) #--- Wait until one thread stop... stopped_service = None while(stopped_service is None): for service in service_list: if not service.is_alive(): log.info("Service %s is dead", service) stopped_service = service break time.sleep(1) except EnvironmentError as e: log.exception("Picammory failed 1") MailService.send_message("Picammory Error", "EnvironmentError: SprinklermoryServer failed: %d (%s)" % (e.errno, e.strerror)) except Exception as e: log.exception("Picammory failed 2") MailService.send_message("Picammory Error", "Exception: Scheduler failed: %s" % (e)) finally: for service in service_list: service.terminate() log.info( ''' ------------------------ --- Picammory Exit --- ------------------------ ''') sys.exit(1)
def run(self): try: log.info("CamProcessorServer Started") camera_name = config.config['camera']['name'] with CamMotionDetector(self._storage_path) as camMotionDetector: # Take a shot at boot, them every hour on the hour log.info("Start After Boot Picture") # LEDProcessor.green(True) with picamera.PiCamera() as camera: nowtime = datetime.now() imageFilename = "%s-%04d%02d%02d-%02d%02d%02d-Boot.jpg" % ( camera_name, nowtime.year, nowtime.month, nowtime.day, nowtime.hour, nowtime.minute, nowtime.second) imageFilepath = self._periodic_path + imageFilename camera.resolution = (2592, 1944) # camera.hflip = True # camera.vflip = True #camera.exif_tags['EXIF.UserComment'] = b'Garden' camera.start_preview() # Camera warm-up time time.sleep(2) # LEDProcessor.green(False) camera.capture(imageFilepath) # LEDProcessor.green(True) remotePath = ("%04d" % (nowtime.year), "%02d" % (nowtime.month), "%02d" % (nowtime.day)) FtpUploader.upload_move(remotePath, imageFilename, imageFilepath) # LEDProcessor.green(False) # LEDProcessor.red(False) # LEDProcessor.blue(False) self.lastPictureTime = datetime.utcnow().hour while not self._terminate: log.info("Start Motion detection") with picamera.PiCamera() as camera: #camera.led = False # LEDProcessor.camera(False) camera.resolution = (1280, 720) # camera.hflip = True # camera.vflip = True camera.framerate = 6 #camera.video_stabilization = True stream = picamera.PiCameraCircularIO(camera, seconds=5) camera.start_recording(stream, format='h264') try: while not self._terminate: camera.wait_recording(0.2) if camMotionDetector.detect_motion( camera, True): self.process_motion( camera, stream, camMotionDetector) # 'datetime.utcnow().hour' take about 25 usec # 'time.gmtime()[3]' take about 26 usec utc_now_hour = datetime.utcnow().hour if (utc_now_hour != self.lastPictureTime): self.lastPictureTime = utc_now_hour break except Exception as e: log.exception("Motion detection") finally: camera.stop_recording() if (self._terminate): log.info("CamProcessorServer terminated %d" % (self._terminate)) break # Take a shot at boot, them every hour on the hour log.info("Start Periodic Picture") # LEDProcessor.green(True) with picamera.PiCamera() as camera: nowtime = datetime.now() log.info('Periodic Picture') imageFilename = "%s-%04d%02d%02d-%02d0000.jpg" % ( camera_name, nowtime.year, nowtime.month, nowtime.day, nowtime.hour) imageFilepath = self._periodic_path + imageFilename camera.resolution = (2592, 1944) # camera.hflip = True # camera.vflip = True #camera.exif_tags['EXIF.UserComment'] = b'Garden' camera.start_preview() # Camera warm-up time time.sleep(1) # LEDProcessor.green(False) camera.capture(imageFilepath) # LEDProcessor.green(True) remotePath = ('Periodic', "%04d" % (nowtime.year), "%02d" % (nowtime.month), "%02d" % (nowtime.day)) FtpUploader.upload_move(remotePath, imageFilename, imageFilepath) # LEDProcessor.green(False) except EnvironmentError as e: log.exception("CamProcessorServer Daemon failed: %d (%s)" % (e.errno, e.strerror)) except Exception as e: log.exception("CamProcessorServer Daemon failed (Exception)") finally: log.info("CamProcessorServer Daemon Exit.")
def detect_motion(self, camera, debug_detection): motionDetected = False timeStart = time.time() #--- if (CamMotionDetector._frame_processed_count >= 10): CamMotionDetector._frame_processed_fps = CamMotionDetector._frame_processed_count / ( timeStart - CamMotionDetector._frame_processed_start_time) CamMotionDetector._frame_processed_count = 0 CamMotionDetector._frame_processed_start_time = timeStart else: CamMotionDetector._frame_processed_count += 1 #--- # finish to dump previous ymi file before to process next dectection if (CamMotionDetector._frame_before_ymi_dump < 0): pass elif (CamMotionDetector._frame_before_ymi_dump > 0): CamMotionDetector._frame_before_ymi_dump -= 1 else: # Dump images used for detection up to detection time filename = self._motionDetectedPrefixFilename + ".ymi" filepath = self._motionDebugPath + filename write_image_buffer(filepath) FtpUploader.upload_move(self.remotePath, filename, filepath) CamMotionDetector._frame_before_ymi_dump = -1 #--- stream = io.BytesIO() camera.capture(stream, format='yuv', resize=(CamMotionDetector._detectionImageWidth, CamMotionDetector._detectionImageHeight), use_video_port=True) stream.seek(0) time1 = time.time() - timeStart timeStart2 = time.time() if self._buffer1 is None: #self._buffer1 = bytearray(stream.getbuffer()) self._buffer1 = stream.getbuffer() else: #--- Motion Detection ----------------------------------------------- # Compare current_image to prior_image to detect motion. # Buffer packed 4 byte per pixel, line after line. (RGBA)(RGBA) # process on a copy improve performance by 30%. but we cannot modify image buffer anymore #self._buffer2 = bytearray(stream.getbuffer()) self._buffer2 = stream.getbuffer() motionDetected = detect_motion(self._buffer1, self._buffer2) self._buffer1 = self._buffer2 time2 = time.time() - timeStart2 #self._counter_debug_dump += 1 # Debug when threshold is reached #if (motionDetected or self._counter_debug_dump >= 10): if (motionDetected and debug_detection): #self._counter_debug_dump = 0 timeStart3 = time.time() nowtime = datetime.now() camera_name = config.config['camera']['name'] self._motionDetectedPrefixFilename = "%s-%04d%02d%02d-%02d%02d%02d" % ( camera_name, nowtime.year, nowtime.month, nowtime.day, nowtime.hour, nowtime.minute, nowtime.second) self.remotePath = ("%04d" % (nowtime.year), "%02d" % (nowtime.month), "%02d/" % (nowtime.day)) #--- # Schedule YMI file generation (if not yet scheduled) if (CamMotionDetector._frame_before_ymi_dump < 0): CamMotionDetector._frame_before_ymi_dump = 180 #--- filename = self._motionDetectedPrefixFilename + ".tiff" filepath = self._motionDebugPath + filename img = Image.frombuffer( "CMYK", (self._detectionImageWidth, self._detectionImageHeight), self._debugImageData, 'raw', "CMYK", 0, 1) img.save(filepath) FtpUploader.upload_move(self.remotePath, filename, filepath) #--- if (motionDetected): filename = self._motionDetectedPrefixFilename + ".txt" else: filename = self._motionDetectedPrefixFilename + "-debug.txt" filepath = self._motionDebugPath + filename time3 = time.time() - timeStart3 with open(filepath, "w") as file: file.write( "Cam Motion Detector: [%d,%d] noiseLevel=%d noiseLevelForHistory=%d sensitivity=%d\n" % (self._detectionImageWidth, self._detectionImageHeight, CamMotionDetector._noiseLevel, CamMotionDetector._noiseLevelForHistory, CamMotionDetector._sensitivity)) file.write( "Motion Detection: {:.0f} fps (capture {:.0f} ms | processing {:.0f} ms | dump {:.0f} ms)\n" .format(CamMotionDetector._frame_processed_fps, 1000 * time1, 1000 * time2, 1000 * time3)) file.write(motion_message()) FtpUploader.upload_move(self.remotePath, filename, filepath) #--- #--- time4 = time.time() - timeStart return motionDetected
def process_motion(self, camera, stream, camMotionDetector): # As soon as we detect motion, split the recording to # record the frames "after" motion detectionTime = datetime.now() nowtime = detectionTime # To be safe, limit to 60s video startDetectionTime = time.time() endDetectionTime = startDetectionTime + 60 camera_name = config.config['camera']['name'] preFilename = "%s-%04d%02d%02d-%02d%02d%02d" % ( camera_name, detectionTime.year, detectionTime.month, detectionTime.day, detectionTime.hour, detectionTime.minute, detectionTime.second) beforeFilename = preFilename + "-1.h264" afterFilename = preFilename + "-2.h264" mergeFilename = preFilename + ".mp4" beforeFilepath = self._storage_path + beforeFilename afterFilepath = self._storage_path + afterFilename mergeFilepath = self._storage_path + mergeFilename #log.info( "%s - Saved After Video to %s" % (progname, afterFilename)) camera.split_recording(afterFilepath) #--- # Always record at least 5s (or 15 frames @ 3fps) of video per event # Need to call detect_motion to keep feeding the yim file for i in range(15): camMotionDetector.detect_motion(camera, False) camera.wait_recording(0.2) # Wait until motion is no longer detected (+5s or 15 frames @ 3fps), then split # recording back to the in-memory circular buffer no_motion = 0 while (no_motion < 15 and time.time() < endDetectionTime): if (camMotionDetector.detect_motion(camera, False)): no_motion = 0 else: no_motion += 1 camera.wait_recording(0.2) #--- # Write the entire content of the circular buffer to disk. No need to # lock the stream here as we're definitely not writing to it # simultaneously #print( "%s - Saved Before Video to %s" % (filename)) with io.open(beforeFilepath, 'wb') as output: for frame in stream.frames: if frame.header: stream.seek(frame.position) break while True: buf = stream.read1() if not buf: break output.write(buf) # Wipe the circular stream once we're done stream.seek(0) stream.truncate() log.info('Motion stopped! no_motion=%d, elapseTime=%fs' % (no_motion, (time.time() - startDetectionTime))) camera.split_recording(stream) # LEDProcessor.red(True) remotePath = ("%04d" % (nowtime.year), "%02d" % (nowtime.month), "%02d" % (nowtime.day)) FtpUploader.merge_convert_and_upload_move(beforeFilepath, afterFilepath, remotePath, mergeFilename, mergeFilepath) log.info('Motion detected!')
def detect_motion(self, camera, debug_detection): motionDetected = False timeStart = time.time() # --- if CamMotionDetector._frame_processed_count >= 10: CamMotionDetector._frame_processed_fps = CamMotionDetector._frame_processed_count / ( timeStart - CamMotionDetector._frame_processed_start_time ) CamMotionDetector._frame_processed_count = 0 CamMotionDetector._frame_processed_start_time = timeStart else: CamMotionDetector._frame_processed_count += 1 # --- # finish to dump previous ymi file before to process next dectection if CamMotionDetector._frame_before_ymi_dump < 0: pass elif CamMotionDetector._frame_before_ymi_dump > 0: CamMotionDetector._frame_before_ymi_dump -= 1 else: # Dump images used for detection up to detection time filename = self._motionDetectedPrefixFilename + ".ymi" filepath = self._motionDebugPath + filename write_image_buffer(filepath) FtpUploader.upload_move(self.remotePath, filename, filepath) CamMotionDetector._frame_before_ymi_dump = -1 # --- stream = io.BytesIO() camera.capture( stream, format="yuv", resize=(CamMotionDetector._detectionImageWidth, CamMotionDetector._detectionImageHeight), use_video_port=True, ) stream.seek(0) time1 = time.time() - timeStart timeStart2 = time.time() if self._buffer1 is None: # self._buffer1 = bytearray(stream.getbuffer()) self._buffer1 = stream.getbuffer() else: # --- Motion Detection ----------------------------------------------- # Compare current_image to prior_image to detect motion. # Buffer packed 4 byte per pixel, line after line. (RGBA)(RGBA) # process on a copy improve performance by 30%. but we cannot modify image buffer anymore # self._buffer2 = bytearray(stream.getbuffer()) self._buffer2 = stream.getbuffer() motionDetected = detect_motion(self._buffer1, self._buffer2) self._buffer1 = self._buffer2 time2 = time.time() - timeStart2 # self._counter_debug_dump += 1 # Debug when threshold is reached # if (motionDetected or self._counter_debug_dump >= 10): if motionDetected and debug_detection: # self._counter_debug_dump = 0 timeStart3 = time.time() nowtime = datetime.now() camera_name = config.config["camera"]["name"] self._motionDetectedPrefixFilename = "%s-%04d%02d%02d-%02d%02d%02d" % ( camera_name, nowtime.year, nowtime.month, nowtime.day, nowtime.hour, nowtime.minute, nowtime.second, ) self.remotePath = ("%04d" % (nowtime.year), "%02d" % (nowtime.month), "%02d/" % (nowtime.day)) # --- # Schedule YMI file generation (if not yet scheduled) if CamMotionDetector._frame_before_ymi_dump < 0: CamMotionDetector._frame_before_ymi_dump = 180 # --- filename = self._motionDetectedPrefixFilename + ".tiff" filepath = self._motionDebugPath + filename img = Image.frombuffer( "CMYK", (self._detectionImageWidth, self._detectionImageHeight), self._debugImageData, "raw", "CMYK", 0, 1, ) img.save(filepath) FtpUploader.upload_move(self.remotePath, filename, filepath) # --- if motionDetected: filename = self._motionDetectedPrefixFilename + ".txt" else: filename = self._motionDetectedPrefixFilename + "-debug.txt" filepath = self._motionDebugPath + filename time3 = time.time() - timeStart3 with open(filepath, "w") as file: file.write( "Cam Motion Detector: [%d,%d] noiseLevel=%d noiseLevelForHistory=%d sensitivity=%d\n" % ( self._detectionImageWidth, self._detectionImageHeight, CamMotionDetector._noiseLevel, CamMotionDetector._noiseLevelForHistory, CamMotionDetector._sensitivity, ) ) file.write( "Motion Detection: {:.0f} fps (capture {:.0f} ms | processing {:.0f} ms | dump {:.0f} ms)\n".format( CamMotionDetector._frame_processed_fps, 1000 * time1, 1000 * time2, 1000 * time3 ) ) file.write(motion_message()) FtpUploader.upload_move(self.remotePath, filename, filepath) # --- # --- time4 = time.time() - timeStart return motionDetected
def run(self): try: log.info("CamProcessorServer Started") camera_name = config.config['camera']['name'] with CamMotionDetector(self._storage_path) as camMotionDetector: # Take a shot at boot, them every hour on the hour log.info("Start After Boot Picture") # LEDProcessor.green(True) with picamera.PiCamera() as camera: nowtime = datetime.now() imageFilename = "%s-%04d%02d%02d-%02d%02d%02d-Boot.jpg" % (camera_name, nowtime.year, nowtime.month, nowtime.day, nowtime.hour, nowtime.minute, nowtime.second) imageFilepath = self._periodic_path + imageFilename camera.resolution = (2592, 1944) # camera.hflip = True # camera.vflip = True #camera.exif_tags['EXIF.UserComment'] = b'Garden' camera.start_preview() # Camera warm-up time time.sleep(2) # LEDProcessor.green(False) camera.capture(imageFilepath) # LEDProcessor.green(True) remotePath = ("%04d" % (nowtime.year), "%02d" % (nowtime.month), "%02d" % (nowtime.day)) FtpUploader.upload_move(remotePath, imageFilename, imageFilepath) # LEDProcessor.green(False) # LEDProcessor.red(False) # LEDProcessor.blue(False) self.lastPictureTime = datetime.utcnow().hour; while not self._terminate: log.info("Start Motion detection") with picamera.PiCamera() as camera: #camera.led = False # LEDProcessor.camera(False) camera.resolution = (1280, 720) # camera.hflip = True # camera.vflip = True camera.framerate = 6 #camera.video_stabilization = True stream = picamera.PiCameraCircularIO(camera, seconds=5) camera.start_recording(stream, format='h264') try: while not self._terminate: camera.wait_recording(0.2) if camMotionDetector.detect_motion(camera, True): self.process_motion(camera, stream, camMotionDetector) # 'datetime.utcnow().hour' take about 25 usec # 'time.gmtime()[3]' take about 26 usec utc_now_hour = datetime.utcnow().hour; if (utc_now_hour != self.lastPictureTime): self.lastPictureTime = utc_now_hour break except Exception as e: log.exception("Motion detection") finally: camera.stop_recording() if (self._terminate): log.info("CamProcessorServer terminated %d" % (self._terminate)) break # Take a shot at boot, them every hour on the hour log.info("Start Periodic Picture") # LEDProcessor.green(True) with picamera.PiCamera() as camera: nowtime = datetime.now() log.info('Periodic Picture') imageFilename = "%s-%04d%02d%02d-%02d0000.jpg" % (camera_name, nowtime.year, nowtime.month, nowtime.day, nowtime.hour) imageFilepath = self._periodic_path + imageFilename camera.resolution = (2592, 1944) # camera.hflip = True # camera.vflip = True #camera.exif_tags['EXIF.UserComment'] = b'Garden' camera.start_preview() # Camera warm-up time time.sleep(1) # LEDProcessor.green(False) camera.capture(imageFilepath) # LEDProcessor.green(True) remotePath = ('Periodic', "%04d" % (nowtime.year), "%02d" % (nowtime.month), "%02d" % (nowtime.day)) FtpUploader.upload_move(remotePath, imageFilename, imageFilepath) # LEDProcessor.green(False) except EnvironmentError as e: log.exception("CamProcessorServer Daemon failed: %d (%s)" % (e.errno, e.strerror)) except Exception as e: log.exception("CamProcessorServer Daemon failed (Exception)") finally: log.info("CamProcessorServer Daemon Exit.")
def process_motion(self, camera, stream, camMotionDetector): # As soon as we detect motion, split the recording to # record the frames "after" motion detectionTime = datetime.now() nowtime = detectionTime # To be safe, limit to 60s video startDetectionTime = time.time() endDetectionTime = startDetectionTime + 60 camera_name = config.config['camera']['name'] preFilename = "%s-%04d%02d%02d-%02d%02d%02d" % (camera_name, detectionTime.year, detectionTime.month, detectionTime.day, detectionTime.hour, detectionTime.minute, detectionTime.second) beforeFilename = preFilename + "-1.h264" afterFilename = preFilename + "-2.h264" mergeFilename = preFilename + ".mp4" beforeFilepath = self._storage_path + beforeFilename afterFilepath = self._storage_path + afterFilename mergeFilepath = self._storage_path + mergeFilename #log.info( "%s - Saved After Video to %s" % (progname, afterFilename)) camera.split_recording(afterFilepath) #--- # Always record at least 5s (or 15 frames @ 3fps) of video per event # Need to call detect_motion to keep feeding the yim file for i in range(15): camMotionDetector.detect_motion(camera, False) camera.wait_recording(0.2) # Wait until motion is no longer detected (+5s or 15 frames @ 3fps), then split # recording back to the in-memory circular buffer no_motion = 0 while(no_motion < 15 and time.time() < endDetectionTime): if (camMotionDetector.detect_motion(camera, False)): no_motion = 0 else: no_motion += 1 camera.wait_recording(0.2) #--- # Write the entire content of the circular buffer to disk. No need to # lock the stream here as we're definitely not writing to it # simultaneously #print( "%s - Saved Before Video to %s" % (filename)) with io.open(beforeFilepath, 'wb') as output: for frame in stream.frames: if frame.header: stream.seek(frame.position) break while True: buf = stream.read1() if not buf: break output.write(buf) # Wipe the circular stream once we're done stream.seek(0) stream.truncate() log.info('Motion stopped! no_motion=%d, elapseTime=%fs' % (no_motion, (time.time() - startDetectionTime))) camera.split_recording(stream) # LEDProcessor.red(True) remotePath = ("%04d" % (nowtime.year), "%02d" % (nowtime.month), "%02d" % (nowtime.day)) FtpUploader.merge_convert_and_upload_move(beforeFilepath, afterFilepath, remotePath, mergeFilename, mergeFilepath) log.info('Motion detected!')
def run(self): service_list = [] try: log.info(""" ---------------------------- --- Picammory Starting --- ---------------------------- """) os.chdir(os.path.expanduser('~/picammory/picammory/')) log.info("os.getcwd() = '%s'", os.getcwd()) #--- # for gpio_pin in (5, 23, 24, 25): # subprocess.call(['/usr/local/bin/gpio', 'export', str(gpio_pin), 'out']) # wiringpi2.wiringPiSetupSys() #--- config.config_load('picammory.ini') #--- # LEDProcessor.start() # service_list.append(LEDProcessor) # # LEDProcessor.blue(True) #--- MailService.start() service_list.append(MailService) MailService.send_message('Picammory', 'Picammory Server Starting') # LEDProcessor.green(True) #--- FtpUploader.start() service_list.append(FtpUploader) # LEDProcessor.red(True) #--- log.info("Start Cam Processor") self.cam_processor = CamProcessor( os.path.expanduser('~/picammory_storage/')) service_list.append(self.cam_processor) # LEDProcessor.blue(False) #--- # LEDProcessor.green(False) # LEDProcessor.red(False) #--- Wait until one thread stop... stopped_service = None while (stopped_service is None): for service in service_list: if not service.is_alive(): log.info("Service %s is dead", service) stopped_service = service break time.sleep(1) except EnvironmentError as e: log.exception("Picammory failed 1") MailService.send_message( "Picammory Error", "EnvironmentError: SprinklermoryServer failed: %d (%s)" % (e.errno, e.strerror)) except Exception as e: log.exception("Picammory failed 2") MailService.send_message("Picammory Error", "Exception: Scheduler failed: %s" % (e)) finally: for service in service_list: service.terminate() log.info(''' ------------------------ --- Picammory Exit --- ------------------------ ''') sys.exit(1)