From 4d788a28179e0856170b1ffdc2d2886e935a79a1 Mon Sep 17 00:00:00 2001 From: Joe Knapper Date: Tue, 10 Feb 2026 22:13:09 +0000 Subject: [PATCH] Remove flash from stage baseclass, add to sim config --- ofm_config_simulation.json | 1 + .../things/camera/simulation.py | 8 ++++--- .../things/illumination.py | 21 ++++++++++++++++--- .../things/stage/dummy.py | 19 +---------------- .../things/stage/sangaboard.py | 3 +-- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/ofm_config_simulation.json b/ofm_config_simulation.json index b061dbd8..21b97694 100644 --- a/ofm_config_simulation.json +++ b/ofm_config_simulation.json @@ -4,6 +4,7 @@ "stage": "openflexure_microscope_server.things.stage.dummy:DummyStage", "autofocus": "openflexure_microscope_server.things.autofocus:AutofocusThing", "camera_stage_mapping": "openflexure_microscope_server.things.camera_stage_mapping:CameraStageMapper", + "illumination": "openflexure_microscope_server.things.illumination.SimulatorIllumination", "system": "openflexure_microscope_server.things.system:OpenFlexureSystem", "smart_scan": { "class": "openflexure_microscope_server.things.smart_scan:SmartScanThing", diff --git a/src/openflexure_microscope_server/things/camera/simulation.py b/src/openflexure_microscope_server/things/camera/simulation.py index c22b32e6..730a6539 100644 --- a/src/openflexure_microscope_server/things/camera/simulation.py +++ b/src/openflexure_microscope_server/things/camera/simulation.py @@ -341,19 +341,21 @@ class SimulatedCamera(BaseCamera): return pl_img.resize((self.shape[1], self.shape[0]), Image.Resampling.BILINEAR) @lt.action - def set_led(self, led_on: bool = True, led_channel=None): + def set_led(self, led_on: bool = True, led_channel: str = None) -> None: # noqa: ARG002 + """Set the simulated LED to on or off.""" if led_on: self.mult = 1 else: self.mult = 0 - def generate_frame(self) -> Image.Image: """Generate a frame with blobs based on the stage coordinates.""" pos = self._stage.instantaneous_position frame = self.generate_image((pos["y"], pos["x"], pos["z"])) # Simulate LED turning off by setting all channels to 0 - return frame * self.mult + if self.mult == 0: + return Image.new(frame.mode, frame.size, 0) + return frame def __enter__(self) -> Self: """Start the capture thread when the Thing context manager is opened.""" diff --git a/src/openflexure_microscope_server/things/illumination.py b/src/openflexure_microscope_server/things/illumination.py index 7cfddf50..d1d5e193 100644 --- a/src/openflexure_microscope_server/things/illumination.py +++ b/src/openflexure_microscope_server/things/illumination.py @@ -1,10 +1,13 @@ +"""A module to handle the illumination in LabThings.""" + import time from typing import Literal import labthings_fastapi as lt +from .camera import BaseCamera from .stage import BaseStage -from .camera import BaseCam + class Illumination(lt.Thing): """Abstract illumination controller.""" @@ -17,9 +20,10 @@ class Illumination(lt.Thing): ) -> None: """Flash the illumination source.""" raise NotImplementedError( - 'Flashing the LED can only be done from the simulator or sangaboard' + "Flashing the LED can only be done from the simulator or sangaboard" ) + class SangaIllumination(Illumination): """Illumination driven by a Sangaboard.""" @@ -32,16 +36,22 @@ class SangaIllumination(Illumination): dt: float = 0.5, led_channel: Literal["cc"] = "cc", ) -> None: + """Flash an LED a given number of times. + + Flashes the LED on channel led_channel number_of_flashes times, + for a duration of dt each. + """ for _ in range(number_of_flashes): self._stage.set_led(False, led_channel) time.sleep(dt) self._stage.set_led(True, led_channel) time.sleep(dt) + class SimulatorIllumination(Illumination): """Illumination control in the simulator.""" - _cam: BaseCam = lt.thing_slot() + _cam: BaseCamera = lt.thing_slot() @lt.action def flash( @@ -50,6 +60,11 @@ class SimulatorIllumination(Illumination): dt: float = 0.5, led_channel: Literal["cc"] = "cc", ) -> None: + """Flash an LED a given number of times. + + Flashes the LED on channel led_channel number_of_flashes times, + for a duration of dt each. + """ for _ in range(number_of_flashes): self._cam.set_led(False, led_channel) time.sleep(dt) diff --git a/src/openflexure_microscope_server/things/stage/dummy.py b/src/openflexure_microscope_server/things/stage/dummy.py index 82515d17..7130fcb7 100644 --- a/src/openflexure_microscope_server/things/stage/dummy.py +++ b/src/openflexure_microscope_server/things/stage/dummy.py @@ -4,7 +4,7 @@ from __future__ import annotations import time from types import TracebackType -from typing import Any, Literal, Optional, Self +from typing import Any, Optional, Self import labthings_fastapi as lt @@ -18,8 +18,6 @@ class DummyStage(BaseStage): hardware attached. """ - led_on: bool = lt.property(default=True) - def __init__( self, thing_server_interface: lt.ThingServerInterface, @@ -117,18 +115,3 @@ class DummyStage(BaseStage): """ self._hardware_position = dict.fromkeys(self.axis_names, 0) self.instantaneous_position = self._hardware_position - - # led_channel is unused in the simulation, but must exist to match the real API - @lt.action - def flash_led( - self, - number_of_flashes: int = 10, - dt: float = 0.5, - led_channel: Literal["cc"] = "cc", # noqa: ARG002 - ) -> None: - """Flash the LED to identify the board (simulated).""" - for _ in range(number_of_flashes): - self.led_on = False - time.sleep(dt) - self.led_on = True - time.sleep(dt) diff --git a/src/openflexure_microscope_server/things/stage/sangaboard.py b/src/openflexure_microscope_server/things/stage/sangaboard.py index fb313337..9a9b7fe5 100644 --- a/src/openflexure_microscope_server/things/stage/sangaboard.py +++ b/src/openflexure_microscope_server/things/stage/sangaboard.py @@ -197,6 +197,5 @@ class SangaboardThing(BaseStage): if led_on: on_brightness = 0.32 sb.query(f"{led_command} {on_brightness}") - else: + else: sb.query(f"{led_command} 0") -