Update things to have thing_server_interface, and further fixes to properties

This commit is contained in:
Julian Stirling 2025-12-14 13:07:50 +00:00
parent a0b8a71477
commit 5d3aa71b4f
9 changed files with 39 additions and 17 deletions

View file

@ -175,7 +175,7 @@ class BaseCamera(lt.Thing):
lores_mjpeg_stream = lt.outputs.MJPEGStreamDescriptor() lores_mjpeg_stream = lt.outputs.MJPEGStreamDescriptor()
_memory_buffer = CameraMemoryBuffer() _memory_buffer = CameraMemoryBuffer()
def __init__(self) -> None: def __init__(self, thing_server_interface: lt.ThingServerInterface) -> None:
"""Initialise the base camera, this creates the background detectors. """Initialise the base camera, this creates the background detectors.
This must be run by all child camera classes. This must be run by all child camera classes.
@ -183,7 +183,7 @@ class BaseCamera(lt.Thing):
To add a new background detector to the server it must be added to the To add a new background detector to the server it must be added to the
dictionary in this function. Configuration will be added at a later date. dictionary in this function. Configuration will be added at a later date.
""" """
super().__init__() super().__init__(thing_server_interface)
self.background_detectors = { self.background_detectors = {
"Colour Channels (LUV)": ColourChannelDetectLUV(), "Colour Channels (LUV)": ColourChannelDetectLUV(),
"Channel Deviations (LUV)": ChannelDeviationLUV(), "Channel Deviations (LUV)": ChannelDeviationLUV(),

View file

@ -27,12 +27,14 @@ LOGGER = logging.getLogger(__name__)
class OpenCVCamera(BaseCamera): class OpenCVCamera(BaseCamera):
"""A Thing that provides and interface to an OpenCV Camera.""" """A Thing that provides and interface to an OpenCV Camera."""
def __init__(self, camera_index: int = 0) -> None: def __init__(
self, thing_server_interface: lt.ThingServerInterface, camera_index: int = 0
) -> None:
"""Iniatilise the thing storing the index of the camera to use. """Iniatilise the thing storing the index of the camera to use.
:param camera_index: The index of the camera to use for the microscope. :param camera_index: The index of the camera to use for the microscope.
""" """
super().__init__() super().__init__(thing_server_interface)
self.camera_index = camera_index self.camera_index = camera_index
self._capture_thread: Optional[Thread] = None self._capture_thread: Optional[Thread] = None
self._capture_enabled = False self._capture_enabled = False

View file

@ -128,7 +128,12 @@ class StreamingPiCamera2(BaseCamera):
generalisation. generalisation.
""" """
def __init__(self, camera_num: int = 0, camera_board: str = "picamera_v2") -> None: def __init__(
self,
thing_server_interface: lt.ThingServerInterface,
camera_num: int = 0,
camera_board: str = "picamera_v2",
) -> None:
"""Initialise the camera with the given camera number. """Initialise the camera with the given camera number.
This makes no connection to the camera (except to get the default tuning file). This makes no connection to the camera (except to get the default tuning file).
@ -138,7 +143,7 @@ class StreamingPiCamera2(BaseCamera):
:param camera_board: The camera board used. Supported options are "picamera_v2" :param camera_board: The camera board used. Supported options are "picamera_v2"
and "picamera_hq". and "picamera_hq".
""" """
super().__init__() super().__init__(thing_server_interface)
self._setting_save_in_progress = False self._setting_save_in_progress = False
self._camera_num = camera_num self._camera_num = camera_num
self._camera_board = camera_board self._camera_board = camera_board
@ -175,7 +180,7 @@ class StreamingPiCamera2(BaseCamera):
mjpeg_bitrate: Optional[int] = lt.property(default=100000000) mjpeg_bitrate: Optional[int] = lt.property(default=100000000)
"""Bitrate for MJPEG stream (None for default).""" """Bitrate for MJPEG stream (None for default)."""
stream_active: bool = lt.property(default=False, observable=True, readonly=True) stream_active: bool = lt.property(default=False, readonly=True)
"""Whether the MJPEG stream is active.""" """Whether the MJPEG stream is active."""
def save_settings(self) -> None: def save_settings(self) -> None:

View file

@ -52,6 +52,7 @@ class SimulatedCamera(BaseCamera):
def __init__( def __init__(
self, self,
thing_server_interface: lt.ThingServerInterface,
shape: tuple[int, int, int] = (616, 820, 3), shape: tuple[int, int, int] = (616, 820, 3),
glyph_shape: tuple[int, int, int] = (121, 121, 3), glyph_shape: tuple[int, int, int] = (121, 121, 3),
canvas_shape: tuple[int, int, int] = (3000, 4000, 3), canvas_shape: tuple[int, int, int] = (3000, 4000, 3),
@ -71,7 +72,7 @@ class SimulatedCamera(BaseCamera):
:param frame_interval: Nominally the time between frames on the MJPEG stream, :param frame_interval: Nominally the time between frames on the MJPEG stream,
however the rate may be slower due to calculation time for focus. however the rate may be slower due to calculation time for focus.
""" """
super().__init__() super().__init__(thing_server_interface)
self.shape = shape self.shape = shape
self.glyph_shape = glyph_shape self.glyph_shape = glyph_shape
self.canvas_shape = canvas_shape self.canvas_shape = canvas_shape

View file

@ -103,13 +103,16 @@ class SmartScanThing(lt.Thing):
past scans. past scans.
""" """
def __init__(self, scans_folder: str) -> None: def __init__(
self, thing_server_interface: lt.ThingServerInterface, scans_folder: str
) -> None:
"""Initialise a SmartScanThing saving to and loading from the input directory. """Initialise a SmartScanThing saving to and loading from the input directory.
:param scans_folder: This is the path to the directory where all scans will be :param scans_folder: This is the path to the directory where all scans will be
saved. Any scans already in this directory will be accessible through the saved. Any scans already in this directory will be accessible through the
HTTP interface. HTTP interface.
""" """
super().__init__(thing_server_interface)
self._scan_dir_manager = scan_directories.ScanDirectoryManager(scans_folder) self._scan_dir_manager = scan_directories.ScanDirectoryManager(scans_folder)
self._scan_lock = threading.Lock() self._scan_lock = threading.Lock()

View file

@ -46,7 +46,7 @@ class BaseStage(lt.Thing):
_axis_names = ("x", "y", "z") _axis_names = ("x", "y", "z")
def __init__(self) -> None: def __init__(self, thing_server_interface: lt.ThingServerInterface) -> None:
"""Initialise the stage. """Initialise the stage.
:raises RedefinedBaseMovementError: if ``move_relative`` and/or :raises RedefinedBaseMovementError: if ``move_relative`` and/or
@ -54,6 +54,7 @@ class BaseStage(lt.Thing):
``_hardware_move_relative`` and/or ``_hardware_move_absolute`` instead so ``_hardware_move_relative`` and/or ``_hardware_move_absolute`` instead so
that all code in the child class uses the hardware reference frame. that all code in the child class uses the hardware reference frame.
""" """
super().__init__(thing_server_interface)
self._hardware_position = dict.fromkeys(self._axis_names, 0) self._hardware_position = dict.fromkeys(self._axis_names, 0)
# This must be the last thing the function does in case it is caught in a try. # This must be the last thing the function does in case it is caught in a try.
@ -78,7 +79,7 @@ class BaseStage(lt.Thing):
"""Current position of the stage.""" """Current position of the stage."""
return self._apply_axis_direction(self._hardware_position) return self._apply_axis_direction(self._hardware_position)
moving: bool = lt.property(bool, default=False, readonly=True, observable=True) moving: bool = lt.property(default=False, readonly=True)
"""Whether the stage is in motion.""" """Whether the stage is in motion."""
axis_inverted: Mapping[str, bool] = lt.setting( axis_inverted: Mapping[str, bool] = lt.setting(

View file

@ -19,7 +19,12 @@ class DummyStage(BaseStage):
hardware attached. hardware attached.
""" """
def __init__(self, step_time: float = 0.001, **kwargs: Any) -> None: def __init__(
self,
thing_server_interface: lt.ThingServerInterface,
step_time: float = 0.001,
**kwargs: Any,
) -> None:
"""Initialise the Dummy stage, setting the step_time to adjust the speed. """Initialise the Dummy stage, setting the step_time to adjust the speed.
:param step_time: The time in seconds per "motor" step. The default of 0.001 :param step_time: The time in seconds per "motor" step. The default of 0.001
@ -27,7 +32,7 @@ class DummyStage(BaseStage):
so the speed can be increased. Increasing it too far is problematic if so the speed can be increased. Increasing it too far is problematic if
also doing computationally heavy tasks like simulated image blurring. also doing computationally heavy tasks like simulated image blurring.
""" """
super().__init__(**kwargs) super().__init__(thing_server_interface, **kwargs)
self.step_time = step_time self.step_time = step_time
self.instantaneous_position = self._hardware_position self.instantaneous_position = self._hardware_position

View file

@ -33,7 +33,12 @@ class SangaboardThing(BaseStage):
functionality is accessed by directly querying the serial interface. functionality is accessed by directly querying the serial interface.
""" """
def __init__(self, port: str = None, **kwargs: Any) -> None: def __init__(
self,
thing_server_interface: lt.ThingServerInterface,
port: str = None,
**kwargs: Any,
) -> None:
"""Initialise SangaboardThing. """Initialise SangaboardThing.
Initialise the "Thing", but do not initialise an underlying Initialise the "Thing", but do not initialise an underlying
@ -49,7 +54,7 @@ class SangaboardThing(BaseStage):
self.sangaboard_kwargs = copy(kwargs) self.sangaboard_kwargs = copy(kwargs)
self.sangaboard_kwargs["port"] = port self.sangaboard_kwargs["port"] = port
self._sangaboard_lock = threading.RLock() self._sangaboard_lock = threading.RLock()
super().__init__(**kwargs) super().__init__(thing_server_interface, **kwargs)
def __enter__(self) -> None: def __enter__(self) -> None:
"""Connect to the sangaboard when the Thing context manager is opened.""" """Connect to the sangaboard when the Thing context manager is opened."""

View file

@ -138,9 +138,9 @@ class RangeofMotionThing(lt.Thing):
calibrated_range: int = lt.setting(default=None, readonly=True) calibrated_range: int = lt.setting(default=None, readonly=True)
def __init__(self) -> None: def __init__(self, thing_server_interface: lt.ThingServerInterface) -> None:
"""Initialise and create the lock.""" """Initialise and create the lock."""
super().__init__() super().__init__(thing_server_interface)
self._lock = Lock() self._lock = Lock()
self._stream_resolution: Optional[tuple[int, int]] = None self._stream_resolution: Optional[tuple[int, int]] = None
self._rom_data = RomDataTracker() self._rom_data = RomDataTracker()