From 9cd36a5b7f1c59e325e791766ae213ba2bd3e471 Mon Sep 17 00:00:00 2001 From: jaknapper Date: Fri, 2 May 2025 13:40:15 +0100 Subject: [PATCH 1/2] Optional wait parameters on captures --- src/labthings_picamera2/thing.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/labthings_picamera2/thing.py b/src/labthings_picamera2/thing.py index 965ea07..a8244ab 100644 --- a/src/labthings_picamera2/thing.py +++ b/src/labthings_picamera2/thing.py @@ -8,7 +8,6 @@ import tempfile import time from tempfile import TemporaryDirectory -import uuid from pydantic import BaseModel, BeforeValidator, RootModel @@ -529,7 +528,7 @@ def snap_image(self) -> ArrayModel: def capture_array( self, stream_name: Literal["main", "lores", "raw"] = "main", - wait: Optional[float] = None, + wait: float = None, ) -> ArrayModel: """Acquire one image from the camera and return as an array @@ -549,19 +548,22 @@ def capture_raw( states_getter: GetThingStates, get_states: bool=True, get_processing_inputs: bool=True, + wait: float=None, ) -> RawImageModel: """Capture a raw image This function is intended to be as fast as possible, and will return as soon as an image has been captured. The output format is not intended to be useful, except as input to `raw_to_png`. - + + wait: (Optional, float) Set a timeout in seconds. A TimeoutError is raised if this time is exceeded during capture. Default = None + When used via the HTTP interface, this function returns the data as a `Blob` object, meaning it can be passed to another action without transferring it over the network. """ with self.picamera() as cam: - (buffer, ), parameters = cam.capture_buffers(["raw"]) + (buffer, ), parameters = cam.capture_buffers(["raw"], wait=wait) configuration = cam.camera_configuration() return RawImageModel( image_data = RawBlob.from_bytes(buffer.tobytes()), @@ -703,6 +705,7 @@ def capture_jpeg( self, metadata_getter: GetThingStates, resolution: Literal["lores", "main", "full"] = "main", + wait: float = None, ) -> JPEGBlob: """Acquire one image from the camera as a JPEG @@ -716,6 +719,9 @@ def capture_jpeg( MJPEG stream and reconfigure the camera to capture a full resolution image. + wait: (Optional, float) Set a timeout in seconds. + A TimeoutError is raised if this time is exceeded during capture. Default = None + Note that this always uses the image processing pipeline - to bypass this, you must use a raw capture. """ @@ -727,7 +733,7 @@ def capture_jpeg( # to reconfigure for these if resolution in ("lores", "main") and config[resolution]: with self.picamera() as cam: - cam.capture_file(path, name=resolution, format="jpeg") + cam.capture_file(path, name=resolution, format="jpeg", wait=wait) else: if resolution != "full": logging.warning( @@ -738,7 +744,7 @@ def capture_jpeg( cam.configure(cam.create_still_configuration()) cam.start() logging.info("capturing") - cam.capture_file(path, name="main", format="jpeg") + cam.capture_file(path, name="main", format="jpeg", wait=wait) logging.info("done") # After the file is written, add metadata about the current Things exif_dict = piexif.load(path) From 29ac1cf78264018a3c17e8fdebdb58a8f3c75575 Mon Sep 17 00:00:00 2001 From: jaknapper Date: Fri, 2 May 2025 15:31:35 +0100 Subject: [PATCH 2/2] Default timeout 0.9 seconds, optional type --- src/labthings_picamera2/thing.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/labthings_picamera2/thing.py b/src/labthings_picamera2/thing.py index a8244ab..3bbf347 100644 --- a/src/labthings_picamera2/thing.py +++ b/src/labthings_picamera2/thing.py @@ -528,7 +528,7 @@ def snap_image(self) -> ArrayModel: def capture_array( self, stream_name: Literal["main", "lores", "raw"] = "main", - wait: float = None, + wait: Optional[float] = 0.9, ) -> ArrayModel: """Acquire one image from the camera and return as an array @@ -537,7 +537,9 @@ def capture_array( binary image formats will be added in due course. stream_name: (Optional) The PiCamera2 stream to use, should be one of ["main", "lores", "raw"]. Default = "main" - wait: (Optional, float) Set a timeout in seconds. A TimeoutError is raised if this time is exceeded during capture. Default = None + wait: (Optional, float) Set a timeout in seconds. + A TimeoutError is raised if this time is exceeded during capture. + Default = 0.9s, lower than the 1s timeout default in picamera yaml settings """ with self.picamera() as cam: return cam.capture_array(stream_name, wait = wait) @@ -548,7 +550,7 @@ def capture_raw( states_getter: GetThingStates, get_states: bool=True, get_processing_inputs: bool=True, - wait: float=None, + wait: Optional[float] = 0.9, ) -> RawImageModel: """Capture a raw image @@ -556,7 +558,9 @@ def capture_raw( as soon as an image has been captured. The output format is not intended to be useful, except as input to `raw_to_png`. - wait: (Optional, float) Set a timeout in seconds. A TimeoutError is raised if this time is exceeded during capture. Default = None + wait: (Optional, float) Set a timeout in seconds. + A TimeoutError is raised if this time is exceeded during capture. + Default = 0.9s, lower than the 1s timeout default in picamera yaml settings When used via the HTTP interface, this function returns the data as a `Blob` object, meaning it can be passed to another action without @@ -705,7 +709,7 @@ def capture_jpeg( self, metadata_getter: GetThingStates, resolution: Literal["lores", "main", "full"] = "main", - wait: float = None, + wait: Optional[float] = 0.9, ) -> JPEGBlob: """Acquire one image from the camera as a JPEG @@ -720,7 +724,8 @@ def capture_jpeg( resolution image. wait: (Optional, float) Set a timeout in seconds. - A TimeoutError is raised if this time is exceeded during capture. Default = None + A TimeoutError is raised if this time is exceeded during capture. + Default = 0.9s, lower than the 1s timeout default in picamera yaml settings Note that this always uses the image processing pipeline - to bypass this, you must use a raw capture.