From e5ff1872d4e89ebf1928f418520bb315d78752a5 Mon Sep 17 00:00:00 2001 From: nlef <52351624+nlef@users.noreply.github.com> Date: Wed, 27 Nov 2024 08:54:42 +0300 Subject: [PATCH] remove saving `no_signal` images during timelapse creation --- bot/camera.py | 53 ++++++++++++++++++++++++++++-------- bot/timelapse.py | 7 ++++- scripts/requirements.dev.txt | 2 +- 3 files changed, 49 insertions(+), 13 deletions(-) diff --git a/bot/camera.py b/bot/camera.py index e9ade92..1dbb522 100644 --- a/bot/camera.py +++ b/bot/camera.py @@ -138,6 +138,8 @@ def __init__(self, config: ConfigWrapper, klippy: Klippy, logging_handler: loggi else: self._rotate_code = -10 + self._lapse_missed_frames: int = 0 + if logging_handler: logger.addHandler(logging_handler) if config.bot_config.debug: @@ -230,6 +232,14 @@ def last_frame_duration(self, new_value: int) -> None: if new_value >= 0: self._last_frame_duration = new_value + @property + def lapse_missed_frames(self) -> int: + return self._lapse_missed_frames + + @lapse_missed_frames.setter + def lapse_missed_frames(self, new_value: int) -> None: + self._lapse_missed_frames = new_value + @staticmethod def _create_thumb(image) -> BytesIO: img = Image.fromarray(image[:, :, [2, 1, 0]]) @@ -289,10 +299,14 @@ def _take_raw_frame(self, rgb: bool = True) -> ndarray: if not success: logger.debug("failed to get camera frame for photo") - img = Image.open("../imgs/nosignal.png") - image = numpy.array(img) - img.close() - del img + if rgb: + img = Image.open("../imgs/nosignal.png") + image = numpy.array(img) + img.close() + del img + else: + # image is None + return numpy.empty(0) else: if self._flip_vertically: image = numpy.flipud(image) @@ -376,7 +390,8 @@ def process_video_frame(frame_local): logger.debug("take_video cam read frame execution time: %s millis", (time.time() - st_time) * 1000) if time.time() > time_last_frame + frame_time: time_last_frame = time.time() - frame_list.append(pickle.dumps(frame_loc)) + if success: + frame_list.append(pickle.dumps(frame_loc)) del frame_loc self.cam_cam.release() @@ -417,12 +432,17 @@ def take_lapse_photo(self, gcode: str = "") -> None: Path(self.lapse_dir).mkdir(parents=True, exist_ok=True) # never add self in params there! raw_frame = self._take_raw_frame(rgb=False) + if gcode: try: self._klippy.execute_gcode_script_sync(gcode.strip()) except Exception as ex: logger.error(ex) + if raw_frame.size == 0: + self._lapse_missed_frames += 1 + return + os_nice(15) numpy.savez_compressed(f"{self.lapse_dir}/{time.time()}", raw=raw_frame) @@ -667,8 +687,9 @@ def take_photo(self, ndarr: ndarray = None, force_rotate: bool = True) -> BytesI response.raise_for_status() except HTTPError as err: logger.error("Streamer snapshot get failed\n%s", err) - with Image.open("../imgs/nosignal.png").convert("RGB") as img: - img.save(bio, format="JPEG") + if force_rotate: + with Image.open("../imgs/nosignal.png").convert("RGB") as img: + img.save(bio, format="JPEG") os_nice(0) bio.seek(0) @@ -679,9 +700,18 @@ def take_lapse_photo(self, gcode: str = "") -> None: # Todo: check for space available? Path(self.lapse_dir).mkdir(parents=True, exist_ok=True) with self.take_photo(force_rotate=False) as photo: - filename = f"{self.lapse_dir}/{time.time()}.{self._img_extension}" - with open(filename, "wb") as outfile: - outfile.write(photo.getvalue()) + if gcode: + try: + self._klippy.execute_gcode_script_sync(gcode.strip()) + except Exception as ex: + logger.error(ex) + + if photo.getbuffer().nbytes > 0: + filename = f"{self.lapse_dir}/{time.time()}.{self._img_extension}" + with open(filename, "wb") as outfile: + outfile.write(photo.getvalue()) + else: + self._lapse_missed_frames += 1 def _image_to_frame(self, image_bio: BytesIO): image_bio.seek(0) @@ -724,7 +754,8 @@ def take_video(self) -> Tuple[BytesIO, BytesIO, int, int]: logger.debug("take_video cam read frame execution time: %s millis", (time.time() - st_time) * 1000) if time.time() > time_last_frame + frame_time: time_last_frame = time.time() - frame_list.append(pickle.dumps(frame_loc)) + if frame_loc.getbuffer().nbytes > 0: + frame_list.append(pickle.dumps(frame_loc)) del frame_loc res_fps = len(frame_list) / self._video_duration diff --git a/bot/timelapse.py b/bot/timelapse.py index 53fe3c1..8ad0320 100644 --- a/bot/timelapse.py +++ b/bot/timelapse.py @@ -166,6 +166,7 @@ def is_running(self, new_val: bool) -> None: self._paused = False if new_val: self._add_timelapse_timer() + self._camera.lapse_missed_frames = 0 else: self._remove_timelapse_timer() @@ -274,13 +275,16 @@ async def _send_lapse(self) -> None: if video_bio.getbuffer().nbytes > 52428800: await info_mess.edit_text(text=f"Telegram bots have a 50mb filesize restriction, please retrieve the timelapse from the configured folder\n{video_path}") else: + lapse_caption = f"time-lapse of {gcode_name}" + if self._camera.lapse_missed_frames > 0: + lapse_caption += f"\n{self._camera.lapse_missed_frames} frames missed" await self._bot.send_video( self._chat_id, video=video_bio, thumbnail=thumb_bio, width=width, height=height, - caption=f"time-lapse of {gcode_name}", + caption=lapse_caption, write_timeout=120, disable_notification=self._silent_progress, ) @@ -318,6 +322,7 @@ def stop_all(self) -> None: self._running = False self._paused = False self._last_height = 0.0 + self._camera.lapse_missed_frames = 0 async def parse_timelapse_params(self, message: str) -> None: mass_parts = message.split(sep=" ") diff --git a/scripts/requirements.dev.txt b/scripts/requirements.dev.txt index 751a96c..7465bbf 100644 --- a/scripts/requirements.dev.txt +++ b/scripts/requirements.dev.txt @@ -5,7 +5,7 @@ memory_profiler==0.61.0 mypy==0.982 numpy~=1.26.4 opencv-python~=4.6.0.66 -pipdeptree==2.23.4 +pipdeptree==2.24.0 pre-commit==4.0.1 ; python_version>='3.9' pre-commit==3.5.0 ; python_version<='3.8' pylint==3.2.7