blob: f36120ad8f4647c27b10b3570bfb555341a67786 [file] [log] [blame]
Shad Ansari5e8d0692021-12-08 19:09:34 +00001import paho.mqtt.client as mqtt
2import time
3import os
4import sys
5import threading
6import logging as log
7from multiprocessing import Process, Queue, Value, Array, Lock
8
9import roc
Shad Ansari30a23732021-09-29 23:07:21 -070010
11
12class BaseCamera(object):
Shad Ansari26682be2021-10-26 03:52:35 +000013 process = {} # background process that reads frames from camera
Shad Ansaric9f48d32021-10-25 19:03:34 +000014 frame = {} # frame queue
Shad Ansari5e8d0692021-12-08 19:09:34 +000015 activity_counter = Value('i', 0)
16 cameras = Array('i', [0, 0, 0, 0])
17 lock = Lock()
Shad Ansari30a23732021-09-29 23:07:21 -070018
Shad Ansariec6bbd32021-12-10 20:57:16 +000019 def __init__(self, device, key, mbrlow, mbrhigh, devicegroup, noroc):
Shad Ansari5e8d0692021-12-08 19:09:34 +000020 self.mqttBroker = "localhost"
Shad Ansaric0726e62021-10-04 22:38:53 +000021 self.device = device
Shad Ansari5e8d0692021-12-08 19:09:34 +000022 self.key = key
23 self.mbrlow = mbrlow
24 self.mbrhigh = mbrhigh
25 self.devicegroup = devicegroup
Shad Ansariec6bbd32021-12-10 20:57:16 +000026 self.noroc = noroc
Shad Ansaric9f48d32021-10-25 19:03:34 +000027
Shad Ansari5e8d0692021-12-08 19:09:34 +000028 """Start the background camera process if it isn't running yet."""
29 if BaseCamera.cameras[int(self.device)] == 0:
30 BaseCamera.cameras[int(self.device)] = 1
31 self.last_detected = None
32 self.timer = None
33 self.detected = False
34 BaseCamera.frame[self.device] = Queue(100)
Shad Ansariec6bbd32021-12-10 20:57:16 +000035 self.set_resolution(self.device, "low")
Shad Ansari26682be2021-10-26 03:52:35 +000036 # start background frame process
37 BaseCamera.process[self.device] = Process(target=self._process, args=(self.device))
38 BaseCamera.process[self.device].start()
Shad Ansari30a23732021-09-29 23:07:21 -070039 # wait until frames are available
Shad Ansari60ca8cc2021-11-02 18:46:44 +000040 _ = self.get_frame()
Shad Ansari30a23732021-09-29 23:07:21 -070041
42 def get_frame(self):
43 """Return the current camera frame."""
Shad Ansari30a23732021-09-29 23:07:21 -070044
Shad Ansari60ca8cc2021-11-02 18:46:44 +000045 # blocks
46 return BaseCamera.frame[self.device].get(block=True)
Shad Ansari30a23732021-09-29 23:07:21 -070047
Shad Ansari341ca3a2021-09-30 12:10:00 -070048 def frames(self):
Shad Ansari30a23732021-09-29 23:07:21 -070049 """"Generator that returns frames from the camera."""
Shad Ansari341ca3a2021-09-30 12:10:00 -070050 raise NotImplementedError('Must be implemented by subclasses.')
Shad Ansari30a23732021-09-29 23:07:21 -070051
Shad Ansari26682be2021-10-26 03:52:35 +000052 def _process(self, device):
53 """Camera background process."""
Shad Ansari30a23732021-09-29 23:07:21 -070054 frames_iterator = self.frames()
55 for frame in frames_iterator:
Shad Ansaric9f48d32021-10-25 19:03:34 +000056 BaseCamera.frame[device].put(frame, block=True)
Shad Ansari4ae11682021-10-22 18:51:53 +000057
Shad Ansari26682be2021-10-26 03:52:35 +000058 BaseCamera.process[device] = None
Shad Ansari5e8d0692021-12-08 19:09:34 +000059
60 def person_detected(self, num):
61 self.last_detected = time.time()
62 if not self.detected:
63 BaseCamera.lock.acquire()
64 BaseCamera.activity_counter.value += 1
65 BaseCamera.lock.release()
66 self.set_resolution_high()
Shad Ansariec6bbd32021-12-10 20:57:16 +000067 if self.noroc is True:
68 roc.set_mbr(self.key, self.devicegroup, self.mbrhigh)
Shad Ansari5e8d0692021-12-08 19:09:34 +000069 self.detected = True
70 self.start_timer()
71
72 def no_person_detected(self):
73 self.detected = False
74 self.timer = None
75 BaseCamera.lock.acquire()
76 BaseCamera.activity_counter.value -=1
77 if BaseCamera.activity_counter.value <= 0:
78 BaseCamera.activity_counter.value = 0
79 self.set_resolution_low()
Shad Ansariec6bbd32021-12-10 20:57:16 +000080 if self.noroc is True:
81 roc.set_mbr(self.key, self.devicegroup, self.mbrlow)
Shad Ansari5e8d0692021-12-08 19:09:34 +000082 BaseCamera.lock.release()
83
84
85 def start_timer(self):
86 # log.info("Start timer for device {}".format(device))
87 self.timer = threading.Timer(10.0, self.timer_expiry)
88 self.timer.start()
89
90
91 def set_resolution_high(self):
92 for device in range(0, 4):
93 self.set_resolution(str(device), "high")
94
95
96 def set_resolution_low(self):
97 for device in range(0, 4):
98 self.set_resolution(str(device), "low")
99
100
101 def set_resolution(self, device, level):
102 log.info("Setting camera {} resolution to {}".format(device, level))
103 client = mqtt.Client()
104 client.connect(self.mqttBroker)
105 client.publish("camera/" + str(5000 + int(device)), level)
106
107
108 def timer_expiry(self):
109 now = time.time()
110 diff = now - self.last_detected
111 log.info("timer_expiry() - now:{}, last_detected:{}".format(now, self.last_detected))
112 if diff > 5.0:
113 self.no_person_detected()
114 else:
115 # Restart timer since person detected not too long back
116 self.start_timer()