blob: e0018f5860f27934e47d48629c1f7bcc0e8c47ee [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
shadf64b92a2022-01-13 19:06:29 +00009from roc import Roc
Shad Ansari925bfe32021-12-14 21:39:10 +000010import config
Shad Ansari30a23732021-09-29 23:07:21 -070011
12
13class BaseCamera(object):
Shad Ansari26682be2021-10-26 03:52:35 +000014 process = {} # background process that reads frames from camera
Shad Ansaric9f48d32021-10-25 19:03:34 +000015 frame = {} # frame queue
Shad Ansari5e8d0692021-12-08 19:09:34 +000016 activity_counter = Value('i', 0)
Shad Ansari925bfe32021-12-14 21:39:10 +000017 cameras = Array('i', [0]*len(config.cameras))
Shad Ansari5e8d0692021-12-08 19:09:34 +000018 lock = Lock()
Shad Ansari30a23732021-09-29 23:07:21 -070019
shadf64b92a2022-01-13 19:06:29 +000020 def __init__(self, device, user, password, mbrlow, mbrhigh, devicegroup, noroc):
Shad Ansari5e8d0692021-12-08 19:09:34 +000021 self.mqttBroker = "localhost"
Shad Ansaric0726e62021-10-04 22:38:53 +000022 self.device = device
Shad Ansari5e8d0692021-12-08 19:09:34 +000023 self.mbrlow = mbrlow
24 self.mbrhigh = mbrhigh
25 self.devicegroup = devicegroup
Shad Ansariec6bbd32021-12-10 20:57:16 +000026 self.noroc = noroc
shadf64b92a2022-01-13 19:06:29 +000027 self.roc = Roc(user, password)
Shad Ansaric9f48d32021-10-25 19:03:34 +000028
Shad Ansari5e8d0692021-12-08 19:09:34 +000029 """Start the background camera process if it isn't running yet."""
30 if BaseCamera.cameras[int(self.device)] == 0:
31 BaseCamera.cameras[int(self.device)] = 1
32 self.last_detected = None
33 self.timer = None
34 self.detected = False
35 BaseCamera.frame[self.device] = Queue(100)
Shad Ansariec6bbd32021-12-10 20:57:16 +000036 self.set_resolution(self.device, "low")
Shad Ansari26682be2021-10-26 03:52:35 +000037 # start background frame process
38 BaseCamera.process[self.device] = Process(target=self._process, args=(self.device))
39 BaseCamera.process[self.device].start()
Shad Ansari30a23732021-09-29 23:07:21 -070040 # wait until frames are available
Shad Ansari60ca8cc2021-11-02 18:46:44 +000041 _ = self.get_frame()
Shad Ansari2eddc1e2022-01-10 17:53:06 +000042 log.info("Start camera {} feed to {}".format(self.device, self.client))
Shad Ansari30a23732021-09-29 23:07:21 -070043
44 def get_frame(self):
45 """Return the current camera frame."""
Shad Ansari30a23732021-09-29 23:07:21 -070046
Shad Ansari60ca8cc2021-11-02 18:46:44 +000047 # blocks
48 return BaseCamera.frame[self.device].get(block=True)
Shad Ansari30a23732021-09-29 23:07:21 -070049
Shad Ansari341ca3a2021-09-30 12:10:00 -070050 def frames(self):
Shad Ansari30a23732021-09-29 23:07:21 -070051 """"Generator that returns frames from the camera."""
Shad Ansari341ca3a2021-09-30 12:10:00 -070052 raise NotImplementedError('Must be implemented by subclasses.')
Shad Ansari30a23732021-09-29 23:07:21 -070053
Shad Ansari26682be2021-10-26 03:52:35 +000054 def _process(self, device):
55 """Camera background process."""
Shad Ansari30a23732021-09-29 23:07:21 -070056 frames_iterator = self.frames()
57 for frame in frames_iterator:
Shad Ansaric9f48d32021-10-25 19:03:34 +000058 BaseCamera.frame[device].put(frame, block=True)
Shad Ansari4ae11682021-10-22 18:51:53 +000059
Shad Ansari26682be2021-10-26 03:52:35 +000060 BaseCamera.process[device] = None
Shad Ansari5e8d0692021-12-08 19:09:34 +000061
62 def person_detected(self, num):
63 self.last_detected = time.time()
64 if not self.detected:
65 BaseCamera.lock.acquire()
66 BaseCamera.activity_counter.value += 1
67 BaseCamera.lock.release()
68 self.set_resolution_high()
Shad Ansari2eddc1e2022-01-10 17:53:06 +000069 if not self.noroc:
shadf64b92a2022-01-13 19:06:29 +000070 self.roc.set_mbr(self.devicegroup, self.mbrhigh)
Shad Ansari5e8d0692021-12-08 19:09:34 +000071 self.detected = True
72 self.start_timer()
73
74 def no_person_detected(self):
75 self.detected = False
76 self.timer = None
77 BaseCamera.lock.acquire()
78 BaseCamera.activity_counter.value -=1
79 if BaseCamera.activity_counter.value <= 0:
80 BaseCamera.activity_counter.value = 0
81 self.set_resolution_low()
Shad Ansari2eddc1e2022-01-10 17:53:06 +000082 if not self.noroc:
shadf64b92a2022-01-13 19:06:29 +000083 self.roc.set_mbr(self.devicegroup, self.mbrlow)
Shad Ansari5e8d0692021-12-08 19:09:34 +000084 BaseCamera.lock.release()
85
86
87 def start_timer(self):
88 # log.info("Start timer for device {}".format(device))
89 self.timer = threading.Timer(10.0, self.timer_expiry)
90 self.timer.start()
91
92
93 def set_resolution_high(self):
Shad Ansari925bfe32021-12-14 21:39:10 +000094 for device in range(0, len(config.cameras)):
Shad Ansari5e8d0692021-12-08 19:09:34 +000095 self.set_resolution(str(device), "high")
96
97
98 def set_resolution_low(self):
Shad Ansari925bfe32021-12-14 21:39:10 +000099 for device in range(0, len(config.cameras)):
Shad Ansari5e8d0692021-12-08 19:09:34 +0000100 self.set_resolution(str(device), "low")
101
102
103 def set_resolution(self, device, level):
104 log.info("Setting camera {} resolution to {}".format(device, level))
105 client = mqtt.Client()
106 client.connect(self.mqttBroker)
107 client.publish("camera/" + str(5000 + int(device)), level)
108
109
110 def timer_expiry(self):
111 now = time.time()
112 diff = now - self.last_detected
shadf64b92a2022-01-13 19:06:29 +0000113 log.debug("timer_expiry() - now:{}, last_detected:{}".format(now, self.last_detected))
Shad Ansari5e8d0692021-12-08 19:09:34 +0000114 if diff > 5.0:
115 self.no_person_detected()
116 else:
117 # Restart timer since person detected not too long back
118 self.start_timer()