import cv2 import time import requests import numpy as np from datetime import datetime import os import json import logging as lg import argparse class CameraMonitor: def __init__(self, config, logger): self.config = config self.logger = logger self.last_detection = 0 def initialize_camera(self): """ Initialize the camera and return the VideoCapture object. """ cap = cv2.VideoCapture(self.config['camera_address']) if not cap.isOpened(): raise Exception(f"Failed to open camera at {self.config['camera_address']}") return cap def log_scene_change(self): """ Log a scene change notification to the Scenesense server. """ current_time = int(time.time()) human_readable_time = datetime.utcfromtimestamp( current_time ).strftime('%Y-%m-%d %H:%M:%S') description = f'Scene change detected at {human_readable_time}' payload = { 'timestamp': current_time, 'description': description } headers = { 'Authorization': self.config['api_key'] } if ( current_time - self.last_detection >= self.config['detection_delay'] ): try: response = requests.post( self.config['api_url'], json=payload, headers=headers ) response.raise_for_status() self.logger.info(f'Scene change logged: {description}') except requests.exceptions.RequestException as e: self.logger.error(f'Error connecting to Scenesense server: {e}') except requests.exceptions.HTTPError as e: self.logger.error(f'HTTP error: {e}') def detect_scene_change(self, previous_frame, current_frame): """ Detect scene change based on frame differences. """ frame_diff = cv2.absdiff(previous_frame, current_frame) mean_diff = np.mean(frame_diff) return mean_diff > self.config['sensitivity_threshold'] def run(self): try: with self.initialize_camera() as cap: previous_frame = None while True: ret, current_frame = cap.read() if not ret: raise Exception("Failed to read frame") if previous_frame is not None: if self.detect_scene_change(previous_frame, current_frame): self.log_scene_change() previous_frame = current_frame except KeyboardInterrupt: self.logger.info("Camera monitoring stopped by user.") except Exception as e: self.logger.error(f"An error occurred: {e}") def parse_command_line_args(): parser = argparse.ArgumentParser(description='Camera Monitor for Scenesense') parser.add_argument('--config', type=str, default='config.json', help='Path to configuration file') return parser.parse_args() def load_config(config_path): try: with open(config_path, 'r') as config_file: return json.load(config_file) except FileNotFoundError: raise Exception(f"Config file not found: {config_path}") except json.JSONDecodeError: raise Exception(f"Invalid JSON format in config file: {config_path}") def setup_logging(log_file='logs/camera_monitor.log'): # logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') # return logging.getLogger('CameraMonitor') # Configure the logger logger = lg.getLogger('CameraMonitor') logger.setLevel(lg.INFO) # Create a TimedRotatingFileHandler for log rotation file_handler = lg.handlers.TimedRotatingFileHandler( log_file, when='midnight', backupCount=7 ) # Keeps logs for 7 days file_handler.suffix = '%Y-%m-%d' # Append date to log file names # Define the log message format formatter = lg.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) file_handler.setFormatter(formatter) # Add the file handler to the logger logger.addHandler(file_handler) return logger def main(): args = parse_command_line_args() config = load_config(args.config) logger = setup_logging() monitor = CameraMonitor(config, logger) monitor.run() if __name__ == "__main__": main()