From 8faa3de4d050b2876fa086dc2cb236bc9d9026d3 Mon Sep 17 00:00:00 2001 From: Gyokhan Kochmarla Date: Mon, 29 Apr 2024 01:15:33 +0300 Subject: [PATCH 1/7] fix: add exceptions to trigger restart --- core/observers/subject/eye_subject.py | 23 ++++++++++++++++++----- core/strategies/eye/base_eye_strategy.py | 5 ++++- core/strategies/eye/picamera_strategy.py | 23 +++++++++++++++-------- 3 files changed, 37 insertions(+), 14 deletions(-) diff --git a/core/observers/subject/eye_subject.py b/core/observers/subject/eye_subject.py index 0d3169f..7f6b877 100644 --- a/core/observers/subject/eye_subject.py +++ b/core/observers/subject/eye_subject.py @@ -81,7 +81,12 @@ def _run_in_loop(self, wifi_lock = Lock() # Save an initial image. - initial_frame = eye_strategy.get_frame() + try: + initial_frame = eye_strategy.get_frame() + except RuntimeError as error: + logger.error( + "[EyeSubject] An error occurred while capturing the frame.") + raise RuntimeError from error file_location = f"{self._image_path}/initial_frame.jpg" cv2.imwrite(file_location, initial_frame) logger.debug("[EyeSubject] Initial frame has been saved.") @@ -89,10 +94,17 @@ def _run_in_loop(self, while True: # If WiFi subject would give rights to use camera, # Check if any intruders detected. - logger.debug("[EyeSubject] WiFi Lock Status: %s", wifi_lock.locked()) + logger.debug("[EyeSubject] WiFi Lock Status: %s", + wifi_lock.locked()) if not wifi_lock.locked(): - result = eye_strategy.check_if_detected() - logger.debug("[EyeSubject] EyeStrategyResult: %s", str(result.result)) + try: + result = eye_strategy.check_if_detected() + except RuntimeError as error: + logger.error( + "[EyeSubject] An error occurred while checking if detected.") + raise RuntimeError from error + logger.debug("[EyeSubject] EyeStrategyResult: %s", + str(result.result)) if result.result: logger.debug("[EyeSubject] Changing state to DETECTED...") @@ -100,7 +112,8 @@ def _run_in_loop(self, self.set_state(EyeStates.DETECTED) sleep_interval = EyeSubject.SLEEP_INTERVAL_DETECTED else: - logger.debug("[EyeSubject] Changing state to NOT_DETECTED...") + logger.debug( + "[EyeSubject] Changing state to NOT_DETECTED...") self.set_state(EyeStates.NOT_DETECTED) sleep_interval = EyeSubject.DEFAULT_SLEEP_INTERVAL diff --git a/core/strategies/eye/base_eye_strategy.py b/core/strategies/eye/base_eye_strategy.py index 1c27e44..2b19ea7 100644 --- a/core/strategies/eye/base_eye_strategy.py +++ b/core/strategies/eye/base_eye_strategy.py @@ -36,7 +36,10 @@ def _detect_humans(self, frame: ndarray) -> DetectorResult: def check_if_detected(self) -> EyeStrategyResult: """This method checks if there are any protectors around.""" #  Get the frame from the camera. - frame = self.get_frame() + try: + frame = self.get_frame() + except RuntimeError as error: + raise RuntimeError from error # Detect humans in the frame. result = self._detect_humans(frame) return EyeStrategyResult(image=result.image, result=result.human_found) diff --git a/core/strategies/eye/picamera_strategy.py b/core/strategies/eye/picamera_strategy.py index 4c008e1..c4805ba 100644 --- a/core/strategies/eye/picamera_strategy.py +++ b/core/strategies/eye/picamera_strategy.py @@ -17,6 +17,7 @@ class PiCameraStrategy(BaseEyeStrategy): """ The camera strategy for eye strategies. """ + def __init__(self): self._detector = None @@ -31,12 +32,18 @@ def get_detector(self) -> BaseDetectorStrategy: def get_frame(self) -> numpy.ndarray: """This method returns the frame from the camera.""" - # Internal attributes - picam2 = Picamera2() - still_configuration = picam2.create_still_configuration(main={"format": 'XRGB8888'}) - picam2.configure(still_configuration) - picam2.start() - frame = picam2.capture_array() - picam2.close() - del picam2 + try: + # Internal attributes + picam2 = Picamera2() + still_configuration = picam2.create_still_configuration( + main={"format": 'XRGB8888'}) + picam2.configure(still_configuration) + picam2.start() + frame = picam2.capture_array() + picam2.close() + del picam2 + except Exception as error: + logger.error( + "An error occurred while capturing the frame: %s", error) + raise RuntimeError from error return cv2.rotate(frame, cv2.ROTATE_90_COUNTERCLOCKWISE) From 02dde30dd05973aa1487af732dc639852726d0a1 Mon Sep 17 00:00:00 2001 From: Gyokhan Kochmarla Date: Mon, 29 Apr 2024 01:36:43 +0300 Subject: [PATCH 2/7] fix: change image capture format and call stop --- core/strategies/eye/picamera_strategy.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/strategies/eye/picamera_strategy.py b/core/strategies/eye/picamera_strategy.py index c4805ba..70a38aa 100644 --- a/core/strategies/eye/picamera_strategy.py +++ b/core/strategies/eye/picamera_strategy.py @@ -36,14 +36,16 @@ def get_frame(self) -> numpy.ndarray: # Internal attributes picam2 = Picamera2() still_configuration = picam2.create_still_configuration( - main={"format": 'XRGB8888'}) + main={"format": 'YUV420'}) picam2.configure(still_configuration) picam2.start() frame = picam2.capture_array() + picam2.stop() picam2.close() del picam2 except Exception as error: logger.error( "An error occurred while capturing the frame: %s", error) raise RuntimeError from error - return cv2.rotate(frame, cv2.ROTATE_90_COUNTERCLOCKWISE) + return cv2.rotate(cv2.cvtColor(frame, cv2.COLOR_YUV420p2RGB), + cv2.ROTATE_90_COUNTERCLOCKWISE) From 8fb42b9e6226ec2df835dabf284ee10d1670d723 Mon Sep 17 00:00:00 2001 From: Gyokhan Kochmarla Date: Mon, 29 Apr 2024 01:51:08 +0300 Subject: [PATCH 3/7] fix: don't call configure each time --- core/strategies/eye/picamera_strategy.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/core/strategies/eye/picamera_strategy.py b/core/strategies/eye/picamera_strategy.py index 70a38aa..8932cc2 100644 --- a/core/strategies/eye/picamera_strategy.py +++ b/core/strategies/eye/picamera_strategy.py @@ -20,6 +20,11 @@ class PiCameraStrategy(BaseEyeStrategy): def __init__(self): self._detector = None + self._picam2 = Picamera2() + still_configuration = self._picam2.create_still_configuration( + main={"format": 'YUV420'} + ) + self._picam2.configure(still_configuration) # Interface methods. def set_detector(self, detector: BaseDetectorStrategy) -> None: @@ -33,16 +38,9 @@ def get_detector(self) -> BaseDetectorStrategy: def get_frame(self) -> numpy.ndarray: """This method returns the frame from the camera.""" try: - # Internal attributes - picam2 = Picamera2() - still_configuration = picam2.create_still_configuration( - main={"format": 'YUV420'}) - picam2.configure(still_configuration) - picam2.start() - frame = picam2.capture_array() - picam2.stop() - picam2.close() - del picam2 + self._picam2.start() + frame = self._picam2.capture_array() + self._picam2.close() except Exception as error: logger.error( "An error occurred while capturing the frame: %s", error) From 9e589601d2567d4dc6d86687d6c489b25290adad Mon Sep 17 00:00:00 2001 From: Gyokhan Kochmarla Date: Mon, 29 Apr 2024 01:54:30 +0300 Subject: [PATCH 4/7] fix: change close to stop --- core/strategies/eye/picamera_strategy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/strategies/eye/picamera_strategy.py b/core/strategies/eye/picamera_strategy.py index 8932cc2..530a92b 100644 --- a/core/strategies/eye/picamera_strategy.py +++ b/core/strategies/eye/picamera_strategy.py @@ -40,7 +40,7 @@ def get_frame(self) -> numpy.ndarray: try: self._picam2.start() frame = self._picam2.capture_array() - self._picam2.close() + self._picam2.stop() except Exception as error: logger.error( "An error occurred while capturing the frame: %s", error) From 65fb22ce361b81e78b711040efd9336922c285da Mon Sep 17 00:00:00 2001 From: Gyokhan Kochmarla Date: Mon, 29 Apr 2024 01:56:46 +0300 Subject: [PATCH 5/7] fix: change yuv420 to xrgb8888 back --- core/strategies/eye/picamera_strategy.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/strategies/eye/picamera_strategy.py b/core/strategies/eye/picamera_strategy.py index 530a92b..05a863c 100644 --- a/core/strategies/eye/picamera_strategy.py +++ b/core/strategies/eye/picamera_strategy.py @@ -22,7 +22,7 @@ def __init__(self): self._detector = None self._picam2 = Picamera2() still_configuration = self._picam2.create_still_configuration( - main={"format": 'YUV420'} + main={"format": 'XRGB8888'} ) self._picam2.configure(still_configuration) @@ -45,5 +45,5 @@ def get_frame(self) -> numpy.ndarray: logger.error( "An error occurred while capturing the frame: %s", error) raise RuntimeError from error - return cv2.rotate(cv2.cvtColor(frame, cv2.COLOR_YUV420p2RGB), + return cv2.rotate(frame, cv2.ROTATE_90_COUNTERCLOCKWISE) From d4eba2011962614355d71b55307236ea6c433ec3 Mon Sep 17 00:00:00 2001 From: Gyokhan Kochmarla Date: Mon, 29 Apr 2024 02:01:31 +0300 Subject: [PATCH 6/7] feat: add memory information command --- servicer.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/servicer.py b/servicer.py index ca84d6e..79c6d04 100644 --- a/servicer.py +++ b/servicer.py @@ -37,7 +37,8 @@ def read_configurations() -> tuple[dict[str, Any], dict[str, Any]]: # Definitations MAIN_CONIGS, STRATEGY_CONFIGS = read_configurations() -SERVICER_BOT = AsyncTeleBot(token=STRATEGY_CONFIGS["telegram_strategy"]["bot_key"]) +SERVICER_BOT = AsyncTeleBot( + token=STRATEGY_CONFIGS["telegram_strategy"]["bot_key"]) KNOWN_LOG_LOCATIONS: dict[str, str] = { "hss.service": "/home/raspberry/.home-security-system/logs/hss.log" } @@ -57,6 +58,7 @@ async def info(message): "/logs hss.service:N - provides the latest N logs.\n" "/inhouse - provides if protectors are in house, and whose.\n" "/imageshot - captures an image and sends.\n" + "/meminfo - provides the memory information.\n" "/reboot - reboots the hardware.\n" "/shell echo 'test'- provides a shell access to the hardware.\n" "/info, /help, /hi - this help text.\n") @@ -147,6 +149,18 @@ async def image_shot(message): del frame, encoded_frame +@SERVICER_BOT.message_handler(commands=['meminfo']) +async def mem_info(message): + """ + This method is called when the /meminfo command is sent. + """ + command = ["cat", "/proc/meminfo"] + process = await asyncio.create_subprocess_shell( + command, stdout=asyncio.subprocess.PIPE) + stdout, _ = await process.communicate() + await SERVICER_BOT.reply_to(message, f"Memory Information: \n{stdout.decode()}") + + @SERVICER_BOT.message_handler(commands=['reboot']) async def reboot(message): """ From 3d34c257ec5e467a69bbf019d8a76dcd19fcfbbe Mon Sep 17 00:00:00 2001 From: Gyokhan Kochmarla Date: Mon, 29 Apr 2024 02:04:09 +0300 Subject: [PATCH 7/7] fix: give command as str --- servicer.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/servicer.py b/servicer.py index 79c6d04..535be31 100644 --- a/servicer.py +++ b/servicer.py @@ -154,9 +154,10 @@ async def mem_info(message): """ This method is called when the /meminfo command is sent. """ - command = ["cat", "/proc/meminfo"] process = await asyncio.create_subprocess_shell( - command, stdout=asyncio.subprocess.PIPE) + "cat /proc/meminfo", + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE) stdout, _ = await process.communicate() await SERVICER_BOT.reply_to(message, f"Memory Information: \n{stdout.decode()}")