|
| 1 | +import os |
| 2 | +import time |
| 3 | +import logging |
| 4 | +import csv |
| 5 | +from datetime import date, datetime |
| 6 | +from collections import deque |
| 7 | +from .utils.mailing import MailService |
| 8 | +from .notifications.slack_notifications import SlackService |
| 9 | + |
| 10 | +logger = logging.getLogger(__name__) |
| 11 | + |
| 12 | + |
| 13 | +class AreaReporting: |
| 14 | + |
| 15 | + def __init__(self, config, area): |
| 16 | + self.processing_alerts = False |
| 17 | + self.config = config |
| 18 | + self.area = area |
| 19 | + |
| 20 | + self.occupancy_sleep_time_interval = float(self.config.get_section_dict("App")["OccupancyAlertsMinInterval"]) |
| 21 | + self.log_dir = self.config.get_section_dict("Logger")["LogDirectory"] |
| 22 | + self.idle_time = float(self.config.get_section_dict('Logger')['TimeInterval']) |
| 23 | + self.area_id = self.area['id'] |
| 24 | + self.area_name = self.area['name'] |
| 25 | + self.occupancy_threshold = self.area['occupancy_threshold'] |
| 26 | + self.should_send_email_notifications = self.area['should_send_email_notifications'] |
| 27 | + self.should_send_slack_notifications = self.area['should_send_slack_notifications'] |
| 28 | + self.cameras = [camera for camera in self.config.get_video_sources() if camera['id'] in self.area['cameras']] |
| 29 | + for camera in self.cameras: |
| 30 | + camera['file_path'] = os.path.join(self.log_dir, camera['id'], "objects_log") |
| 31 | + camera['last_processed_time'] = time.time() |
| 32 | + |
| 33 | + self.mail_service = MailService(config) |
| 34 | + self.slack_service = SlackService(config) |
| 35 | + |
| 36 | + def process_area(self): |
| 37 | + # Sleep for a while so cameras start processing |
| 38 | + time.sleep(30) |
| 39 | + |
| 40 | + self.processing_alerts = True |
| 41 | + logger.info(f'Enabled processing alerts for - {self.area_id}: {self.area_name} with {len(self.cameras)} cameras') |
| 42 | + while self.processing_alerts: |
| 43 | + camera_file_paths = [os.path.join(camera['file_path'], str(date.today()) + ".csv") for camera in self.cameras] |
| 44 | + if not all(list(map(os.path.isfile, camera_file_paths))): |
| 45 | + # Wait before csv for this day are created |
| 46 | + logger.info(f'Area reporting on - {self.area_id}: {self.area_name} is waiting for reports to be created') |
| 47 | + time.sleep(5) |
| 48 | + |
| 49 | + occupancy = 0 |
| 50 | + for camera in self.cameras: |
| 51 | + with open(os.path.join(camera['file_path'], str(date.today()) + ".csv"), 'r') as log: |
| 52 | + last_log = deque(csv.DictReader(log), 1)[0] |
| 53 | + log_time = datetime.strptime(last_log['Timestamp'], "%Y-%m-%d %H:%M:%S") |
| 54 | + # TODO: If the TimeInterval of the Logger is more than 30 seconds this would have to be revised. |
| 55 | + if (datetime.now() - log_time).total_seconds() < 30: |
| 56 | + occupancy += int(last_log['DetectedObjects']) |
| 57 | + else: |
| 58 | + logger.warn(f"Logs aren't being updated for camera {camera['id']} - {camera['name']}") |
| 59 | + |
| 60 | + if occupancy > self.occupancy_threshold: |
| 61 | + # Trigger alerts |
| 62 | + if self.should_send_email_notifications: |
| 63 | + self.mail_service.send_occupancy_notification(self.area, occupancy) |
| 64 | + if self.should_send_slack_notifications: |
| 65 | + self.slack_service.occupancy_alert(self.area, occupancy) |
| 66 | + # Sleep until the cooldown of the alert |
| 67 | + time.sleep(self.occupancy_sleep_time_interval) |
| 68 | + else: |
| 69 | + # Sleep until new data is logged |
| 70 | + time.sleep(self.idle_time) |
| 71 | + |
| 72 | + self.stop_process_area() |
| 73 | + |
| 74 | + def stop_process_area(self): |
| 75 | + logger.info(f'Disabled processing alerts for area - {self.area_id}: {self.area_name}') |
| 76 | + self.processing_alerts = False |
0 commit comments