blob: e97dca25d5bb806d2c4593657b068140b4402aa7 [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 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
Shad Ansariec6bbd32021-12-10 20:57:16 +000020 def __init__(self, device, key, 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.key = key
24 self.mbrlow = mbrlow
25 self.mbrhigh = mbrhigh
26 self.devicegroup = devicegroup
Shad Ansariec6bbd32021-12-10 20:57:16 +000027 self.noroc = noroc
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 Ansari30a23732021-09-29 23:07:21 -070042
43 def get_frame(self):
44 """Return the current camera frame."""
Shad Ansari30a23732021-09-29 23:07:21 -070045
Shad Ansari60ca8cc2021-11-02 18:46:44 +000046 # blocks
47 return BaseCamera.frame[self.device].get(block=True)
Shad Ansari30a23732021-09-29 23:07:21 -070048
Shad Ansari341ca3a2021-09-30 12:10:00 -070049 def frames(self):
Shad Ansari30a23732021-09-29 23:07:21 -070050 """"Generator that returns frames from the camera."""
Shad Ansari341ca3a2021-09-30 12:10:00 -070051 raise NotImplementedError('Must be implemented by subclasses.')
Shad Ansari30a23732021-09-29 23:07:21 -070052
Shad Ansari26682be2021-10-26 03:52:35 +000053 def _process(self, device):
54 """Camera background process."""
Shad Ansari30a23732021-09-29 23:07:21 -070055 frames_iterator = self.frames()
56 for frame in frames_iterator:
Shad Ansaric9f48d32021-10-25 19:03:34 +000057 BaseCamera.frame[device].put(frame, block=True)
Shad Ansari4ae11682021-10-22 18:51:53 +000058
Shad Ansari26682be2021-10-26 03:52:35 +000059 BaseCamera.process[device] = None
Shad Ansari5e8d0692021-12-08 19:09:34 +000060
61 def person_detected(self, num):
62 self.last_detected = time.time()
63 if not self.detected:
64 BaseCamera.lock.acquire()
65 BaseCamera.activity_counter.value += 1
66 BaseCamera.lock.release()
67 self.set_resolution_high()
Shad Ansariec6bbd32021-12-10 20:57:16 +000068 if self.noroc is True:
69 roc.set_mbr(self.key, self.devicegroup, self.mbrhigh)
Shad Ansari5e8d0692021-12-08 19:09:34 +000070 self.detected = True
71 self.start_timer()
72
73 def no_person_detected(self):
74 self.detected = False
75 self.timer = None
76 BaseCamera.lock.acquire()
77 BaseCamera.activity_counter.value -=1
78 if BaseCamera.activity_counter.value <= 0:
79 BaseCamera.activity_counter.value = 0
80 self.set_resolution_low()
Shad Ansariec6bbd32021-12-10 20:57:16 +000081 if self.noroc is True:
82 roc.set_mbr(self.key, self.devicegroup, self.mbrlow)
Shad Ansari5e8d0692021-12-08 19:09:34 +000083 BaseCamera.lock.release()
84
85
86 def start_timer(self):
87 # log.info("Start timer for device {}".format(device))
88 self.timer = threading.Timer(10.0, self.timer_expiry)
89 self.timer.start()
90
91
92 def set_resolution_high(self):
Shad Ansari925bfe32021-12-14 21:39:10 +000093 for device in range(0, len(config.cameras)):
Shad Ansari5e8d0692021-12-08 19:09:34 +000094 self.set_resolution(str(device), "high")
95
96
97 def set_resolution_low(self):
Shad Ansari925bfe32021-12-14 21:39:10 +000098 for device in range(0, len(config.cameras)):
Shad Ansari5e8d0692021-12-08 19:09:34 +000099 self.set_resolution(str(device), "low")
100
101
102 def set_resolution(self, device, level):
103 log.info("Setting camera {} resolution to {}".format(device, level))
104 client = mqtt.Client()
105 client.connect(self.mqttBroker)
106 client.publish("camera/" + str(5000 + int(device)), level)
107
108
109 def timer_expiry(self):
110 now = time.time()
111 diff = now - self.last_detected
112 log.info("timer_expiry() - now:{}, last_detected:{}".format(now, self.last_detected))
113 if diff > 5.0:
114 self.no_person_detected()
115 else:
116 # Restart timer since person detected not too long back
117 self.start_timer()