From aca887be8dc120698ae40f9a785cecf32c225de6 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Sun, 25 Feb 2024 09:27:53 -0600 Subject: [PATCH 01/13] allow custom filenaming --- adafruit_pycamera/__init__.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/adafruit_pycamera/__init__.py b/adafruit_pycamera/__init__.py index d019cf5..8c68479 100644 --- a/adafruit_pycamera/__init__.py +++ b/adafruit_pycamera/__init__.py @@ -820,14 +820,17 @@ def live_preview_mode(self): # self.effect = self._effect self.continuous_capture_start() - def open_next_image(self, extension="jpg"): + def open_next_image(self, extension="jpg", filename_prefix="img"): """Return an opened numbered file on the sdcard, such as "img01234.jpg".""" try: os.stat("/sd") except OSError as exc: # no SD card! raise RuntimeError("No SD card mounted") from exc while True: - filename = "/sd/img%04d.%s" % (self._image_counter, extension) + filename = f"/sd/{filename_prefix}%04d.%s" % ( + self._image_counter, + extension, + ) self._image_counter += 1 try: os.stat(filename) @@ -837,7 +840,7 @@ def open_next_image(self, extension="jpg"): print("Writing to", filename) return open(filename, "wb") - def capture_jpeg(self): + def capture_jpeg(self, filename_prefix="img"): """Capture a jpeg file and save it to the SD card""" try: os.stat("/sd") @@ -855,7 +858,7 @@ def capture_jpeg(self): print(f"Captured {len(jpeg)} bytes of jpeg data") print("Resolution %d x %d" % (self.camera.width, self.camera.height)) - with self.open_next_image() as dest: + with self.open_next_image(filename_prefix=filename_prefix) as dest: chunksize = 16384 for offset in range(0, len(jpeg), chunksize): dest.write(jpeg[offset : offset + chunksize]) From 23c7fa5c288f283603835c3172dbd814851411be Mon Sep 17 00:00:00 2001 From: foamyguy Date: Sun, 25 Feb 2024 10:25:33 -0600 Subject: [PATCH 02/13] timestamp filename example --- examples/timestamp_filename/code.py | 78 +++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 examples/timestamp_filename/code.py diff --git a/examples/timestamp_filename/code.py b/examples/timestamp_filename/code.py new file mode 100644 index 0000000..1022cef --- /dev/null +++ b/examples/timestamp_filename/code.py @@ -0,0 +1,78 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT +""" simple point-and-shoot camera example. With NTP and internal RTC to + add timestamp to photo filenames. Must install adafruit_ntp library!""" + +import time +import adafruit_pycamera # pylint: disable=import-error +import wifi +import socketpool +import adafruit_ntp +import rtc +import time + +pool = socketpool.SocketPool(wifi.radio) +ntp = adafruit_ntp.NTP(pool, tz_offset=0) +rtc.RTC().datetime = ntp.datetime + +pycam = adafruit_pycamera.PyCamera() +pycam.mode = 0 # only mode 0 (JPEG) will work in this example + +# User settings - try changing these: +pycam.resolution = 2 # 0-12 preset resolutions: +# 0: 240x240, 1: 320x240, 2: 640x480, 3: 800x600, 4: 1024x768, +# 5: 1280x720, 6: 1280x1024, 7: 1600x1200, 8: 1920x1080, 9: 2048x1536, +# 10: 2560x1440, 11: 2560x1600, 12: 2560x1920 +pycam.led_level = 1 # 0-4 preset brightness levels +pycam.led_color = 0 # 0-7 preset colors: 0: white, 1: green, 2: yellow, 3: red, +# 4: pink, 5: blue, 6: teal, 7: rainbow +pycam.effect = 0 # 0-7 preset FX: 0: normal, 1: invert, 2: b&w, 3: red, +# 4: green, 5: blue, 6: sepia, 7: solarize + +print("Simple camera ready.") +pycam.tone(800, 0.1) +pycam.tone(1200, 0.05) + +while True: + pycam.blit(pycam.continuous_capture()) + pycam.keys_debounce() + + if pycam.shutter.short_count: + print("Shutter released") + pycam.tone(1200, 0.05) + pycam.tone(1600, 0.05) + try: + pycam.display_message("snap", color=0x00DD00) + timestamp = f"img_{time.localtime().tm_year}-{time.localtime().tm_mon}-{time.localtime().tm_mday}_{time.localtime().tm_hour:02}-{time.localtime().tm_min:02}-{time.localtime().tm_sec:02}_" + pycam.capture_jpeg(filename_prefix=timestamp) + pycam.live_preview_mode() + except TypeError as exception: + pycam.display_message("Failed", color=0xFF0000) + time.sleep(0.5) + pycam.live_preview_mode() + except RuntimeError as exception: + pycam.display_message("Error\nNo SD Card", color=0xFF0000) + time.sleep(0.5) + + if pycam.card_detect.fell: + print("SD card removed") + pycam.unmount_sd_card() + pycam.display.refresh() + + if pycam.card_detect.rose: + print("SD card inserted") + pycam.display_message("Mounting\nSD Card", color=0xFFFFFF) + for _ in range(3): + try: + print("Mounting card") + pycam.mount_sd_card() + print("Success!") + break + except OSError as exception: + print("Retrying!", exception) + time.sleep(0.5) + else: + pycam.display_message("SD Card\nFailed!", color=0xFF0000) + time.sleep(0.5) + pycam.display.refresh() From 994dd1ccef8877b208778171169e076fa889b6a4 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Sun, 25 Feb 2024 10:27:32 -0600 Subject: [PATCH 03/13] pylint fixes --- examples/timestamp_filename/code.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/examples/timestamp_filename/code.py b/examples/timestamp_filename/code.py index 1022cef..03308af 100644 --- a/examples/timestamp_filename/code.py +++ b/examples/timestamp_filename/code.py @@ -5,12 +5,11 @@ add timestamp to photo filenames. Must install adafruit_ntp library!""" import time -import adafruit_pycamera # pylint: disable=import-error import wifi import socketpool -import adafruit_ntp import rtc -import time +import adafruit_ntp +import adafruit_pycamera # pylint: disable=import-error pool = socketpool.SocketPool(wifi.radio) ntp = adafruit_ntp.NTP(pool, tz_offset=0) @@ -44,7 +43,11 @@ pycam.tone(1600, 0.05) try: pycam.display_message("snap", color=0x00DD00) - timestamp = f"img_{time.localtime().tm_year}-{time.localtime().tm_mon}-{time.localtime().tm_mday}_{time.localtime().tm_hour:02}-{time.localtime().tm_min:02}-{time.localtime().tm_sec:02}_" + # pylint: disable=line-too-long + timestamp = ( + f"img_{time.localtime().tm_year}-{time.localtime().tm_mon}-{time.localtime().tm_mday}" + f"_{time.localtime().tm_hour:02}-{time.localtime().tm_min:02}-{time.localtime().tm_sec:02}_" + ) pycam.capture_jpeg(filename_prefix=timestamp) pycam.live_preview_mode() except TypeError as exception: From 91969b403c6edfc4fac63ffaf238bfaf7a3399cf Mon Sep 17 00:00:00 2001 From: foamyguy Date: Sun, 25 Feb 2024 10:30:55 -0600 Subject: [PATCH 04/13] more details in comment --- examples/timestamp_filename/code.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/timestamp_filename/code.py b/examples/timestamp_filename/code.py index 03308af..3ac59d3 100644 --- a/examples/timestamp_filename/code.py +++ b/examples/timestamp_filename/code.py @@ -2,7 +2,10 @@ # # SPDX-License-Identifier: MIT """ simple point-and-shoot camera example. With NTP and internal RTC to - add timestamp to photo filenames. Must install adafruit_ntp library!""" + add timestamp to photo filenames. Must install adafruit_ntp library! + Example code assumes WIFI credentials are properly setup and web workflow + enabled in settings.toml. If not, you'll need to add code to manually connect + to your network.""" import time import wifi From c8d4a046b25520cd9c9d5b6dd7d1c91a0bb1cb15 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Mon, 4 Mar 2024 14:52:23 -0600 Subject: [PATCH 05/13] reduce to single string format. Fix long line in example for CircuitPython --- adafruit_pycamera/__init__.py | 5 +---- examples/timestamp_filename/code.py | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/adafruit_pycamera/__init__.py b/adafruit_pycamera/__init__.py index 8c68479..9b056bc 100644 --- a/adafruit_pycamera/__init__.py +++ b/adafruit_pycamera/__init__.py @@ -827,10 +827,7 @@ def open_next_image(self, extension="jpg", filename_prefix="img"): except OSError as exc: # no SD card! raise RuntimeError("No SD card mounted") from exc while True: - filename = f"/sd/{filename_prefix}%04d.%s" % ( - self._image_counter, - extension, - ) + filename = f"/sd/{filename_prefix}{self._image_counter}.{extension}" self._image_counter += 1 try: os.stat(filename) diff --git a/examples/timestamp_filename/code.py b/examples/timestamp_filename/code.py index 3ac59d3..93f4a8b 100644 --- a/examples/timestamp_filename/code.py +++ b/examples/timestamp_filename/code.py @@ -47,10 +47,7 @@ try: pycam.display_message("snap", color=0x00DD00) # pylint: disable=line-too-long - timestamp = ( - f"img_{time.localtime().tm_year}-{time.localtime().tm_mon}-{time.localtime().tm_mday}" - f"_{time.localtime().tm_hour:02}-{time.localtime().tm_min:02}-{time.localtime().tm_sec:02}_" - ) + timestamp = f"img_{time.localtime().tm_year}-{time.localtime().tm_mon}-{time.localtime().tm_mday}_{time.localtime().tm_hour:02}-{time.localtime().tm_min:02}-{time.localtime().tm_sec:02}_" pycam.capture_jpeg(filename_prefix=timestamp) pycam.live_preview_mode() except TypeError as exception: From 9410a211ae72c14449fe5662c16cfe141a114079 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Mon, 4 Mar 2024 14:59:36 -0600 Subject: [PATCH 06/13] refactor longline to use format() --- examples/timestamp_filename/code.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/examples/timestamp_filename/code.py b/examples/timestamp_filename/code.py index 93f4a8b..3edd7fa 100644 --- a/examples/timestamp_filename/code.py +++ b/examples/timestamp_filename/code.py @@ -47,7 +47,14 @@ try: pycam.display_message("snap", color=0x00DD00) # pylint: disable=line-too-long - timestamp = f"img_{time.localtime().tm_year}-{time.localtime().tm_mon}-{time.localtime().tm_mday}_{time.localtime().tm_hour:02}-{time.localtime().tm_min:02}-{time.localtime().tm_sec:02}_" + timestamp = "img_{}-{}-{}_{:02}-{:02}-{:02}_".format( + time.localtime().tm_year, + time.localtime().tm_mon, + time.localtime().tm_mday, + time.localtime().tm_hour, + time.localtime().tm_min, + time.localtime().tm_sec, + ) pycam.capture_jpeg(filename_prefix=timestamp) pycam.live_preview_mode() except TypeError as exception: From b57c955df4183ac226e3cfec6acd29228cf99b1a Mon Sep 17 00:00:00 2001 From: foamyguy Date: Mon, 4 Mar 2024 15:00:04 -0600 Subject: [PATCH 07/13] remove pylint disable --- examples/timestamp_filename/code.py | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/timestamp_filename/code.py b/examples/timestamp_filename/code.py index 3edd7fa..05c2a2e 100644 --- a/examples/timestamp_filename/code.py +++ b/examples/timestamp_filename/code.py @@ -46,7 +46,6 @@ pycam.tone(1600, 0.05) try: pycam.display_message("snap", color=0x00DD00) - # pylint: disable=line-too-long timestamp = "img_{}-{}-{}_{:02}-{:02}-{:02}_".format( time.localtime().tm_year, time.localtime().tm_mon, From 85d76995c65a0cb37a356fc58263fd4afd5a5e2a Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 5 Mar 2024 11:24:49 -0600 Subject: [PATCH 08/13] leading 0s format --- adafruit_pycamera/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_pycamera/__init__.py b/adafruit_pycamera/__init__.py index 9b056bc..a7cbe35 100644 --- a/adafruit_pycamera/__init__.py +++ b/adafruit_pycamera/__init__.py @@ -827,7 +827,7 @@ def open_next_image(self, extension="jpg", filename_prefix="img"): except OSError as exc: # no SD card! raise RuntimeError("No SD card mounted") from exc while True: - filename = f"/sd/{filename_prefix}{self._image_counter}.{extension}" + filename = f"/sd/{filename_prefix}{self._image_counter:04d}.{extension}" self._image_counter += 1 try: os.stat(filename) From dcdeb5fcfcef4a4c2c8e49745915432b96c5a47b Mon Sep 17 00:00:00 2001 From: foamyguy Date: Mon, 7 Oct 2024 09:24:05 -0500 Subject: [PATCH 09/13] remove deprecated get_html_theme_path() call Signed-off-by: foamyguy --- docs/conf.py | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index cbf1452..9993665 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -137,7 +137,6 @@ import sphinx_rtd_theme html_theme = "sphinx_rtd_theme" -html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), "."] # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, From 3e5695361bd05dbf20be03ccb7239bb7b451f64a Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 14 Jan 2025 11:32:34 -0600 Subject: [PATCH 10/13] add sphinx configuration to rtd.yaml Signed-off-by: foamyguy --- .readthedocs.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index b79ec5b..fe4faae 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -8,6 +8,9 @@ # Required version: 2 +sphinx: + configuration: docs/conf.py + build: os: ubuntu-20.04 tools: From 2aa48460f89a1347991cb05915e7beac9370447d Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 16 Jan 2025 15:33:42 -0600 Subject: [PATCH 11/13] update rtd badge url --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index af6a199..ff8c96e 100644 --- a/README.rst +++ b/README.rst @@ -2,7 +2,7 @@ Introduction ============ -.. image:: https://readthedocs.org/projects/adafruit-circuitpython-pycamera/badge/?version=latest +.. image:: https://readthedocs.org/projects/pycamera/badge/?version=latest :target: https://docs.circuitpython.org/projects/pycamera/en/latest/ :alt: Documentation Status From 9bccbf87204ce4fc81bdffdb90ba1a059cd72a71 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 16 Jan 2025 15:35:00 -0600 Subject: [PATCH 12/13] update rtd badge url --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index ff8c96e..48e9ca9 100644 --- a/README.rst +++ b/README.rst @@ -2,7 +2,7 @@ Introduction ============ -.. image:: https://readthedocs.org/projects/pycamera/badge/?version=latest +.. image:: https://readthedocs.org/projects/circuitpython-pycamera/badge/?version=latest :target: https://docs.circuitpython.org/projects/pycamera/en/latest/ :alt: Documentation Status From 85ede001e8d62edd250c33d2b68138c7e36f2173 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Fri, 17 Jan 2025 15:37:25 -0600 Subject: [PATCH 13/13] last_saved_filename property --- adafruit_pycamera/__init__.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/adafruit_pycamera/__init__.py b/adafruit_pycamera/__init__.py index 32d8e14..1ef4c94 100644 --- a/adafruit_pycamera/__init__.py +++ b/adafruit_pycamera/__init__.py @@ -946,6 +946,13 @@ def blit_overlay_into_last_capture(self): del cc565_swapped gc.collect() + @property + def last_saved_filename(self) -> str: + """ + The filename of the last image saved. + """ + return self._last_saved_image_filename + def continuous_capture_start(self): """Switch the camera to continuous-capture mode""" pass # pylint: disable=unnecessary-pass