Spun off from #14, which consolidated the device layer into a single process.
That refactor is complete, but it left gently/hardware/dispim/device_layer.py
as a ~3,000-line monolith. The goal here is not just "break up a big file" — it's
to split it along the hardware-agnostic vs. diSPIM-specific line, so a second
hardware plugin (e.g. twophoton) reuses the plumbing instead of reimplementing it.
Context: what's already agnostic
The agent/harness already program against hardware-agnostic interfaces — the
Microscope/HTTPMicroscope base (harness/microscope.py), HardwareProtocol +
CAPABILITIES, and the create_device_layer() / create_client() factories. The
boundary is correct. The problem is that a lot of hardware-independent plumbing
is trapped inside the diSPIM plugin, and a new hardware would have to rewrite it.
1. Extract a hardware-agnostic BaseDeviceLayer
Hoist the reusable scaffolding out of device_layer.py into a base class (in
core/harness, building on the existing core/service.py:Service). Generic,
not diSPIM-specific:
- aiohttp routing /
Service lifecycle wiring
- SSE device-state streaming machinery (pollers + broadcast/debounce)
- plan queue + executor
/api/microscope/execute plan-dispatch translation
- SAM / detection endpoint scaffolding
A hardware plugin should subclass this and only supply device/plan specifics.
2. Define the HTTP wire contract once
The /api/* contract (/api/microscope/execute, /api/devices/stream,
/api/detect_embryos, …) is currently defined only inside diSPIM and re-parsed by
hand in three places: dispim/client.py, app/device_state_monitor.py,
harness/microscope.py. Pin it down in one shared schema/dataclass module so
client and server agree by construction.
3. Keep diSPIM-specific code in the plugin
What stays in gently/hardware/dispim/: MMCore init, Ophyd device definitions,
Bluesky plans, dual-view/galvo specifics, the concrete SAM detector, accessory
devices (SwitchBot, temperature, bottom camera).
4. Purge dead RPyC references
Stale comments/handling from the old RPyC transfer path:
gently/hardware/dispim/devices/acquisition.py:216
gently/hardware/dispim/plans/calibration.py:524
Scope guard (deliberately deferred)
There is exactly one hardware plugin today; twophoton is aspirational. To avoid
abstracting the wrong joints from a sample size of one: extract only the obviously
generic plumbing now (1, 2, 4). Defer a "universal" device-layer abstraction until a
real second hardware exists to validate the seams (rule of three).
Spun off from #14, which consolidated the device layer into a single process.
That refactor is complete, but it left
gently/hardware/dispim/device_layer.pyas a ~3,000-line monolith. The goal here is not just "break up a big file" — it's
to split it along the hardware-agnostic vs. diSPIM-specific line, so a second
hardware plugin (e.g. twophoton) reuses the plumbing instead of reimplementing it.
Context: what's already agnostic
The agent/harness already program against hardware-agnostic interfaces — the
Microscope/HTTPMicroscopebase (harness/microscope.py),HardwareProtocol+CAPABILITIES, and thecreate_device_layer()/create_client()factories. Theboundary is correct. The problem is that a lot of hardware-independent plumbing
is trapped inside the diSPIM plugin, and a new hardware would have to rewrite it.
1. Extract a hardware-agnostic
BaseDeviceLayerHoist the reusable scaffolding out of
device_layer.pyinto a base class (incore/harness, building on the existingcore/service.py:Service). Generic,not diSPIM-specific:
Servicelifecycle wiring/api/microscope/executeplan-dispatch translationA hardware plugin should subclass this and only supply device/plan specifics.
2. Define the HTTP wire contract once
The
/api/*contract (/api/microscope/execute,/api/devices/stream,/api/detect_embryos, …) is currently defined only inside diSPIM and re-parsed byhand in three places:
dispim/client.py,app/device_state_monitor.py,harness/microscope.py. Pin it down in one shared schema/dataclass module soclient and server agree by construction.
3. Keep diSPIM-specific code in the plugin
What stays in
gently/hardware/dispim/: MMCore init, Ophyd device definitions,Bluesky plans, dual-view/galvo specifics, the concrete SAM detector, accessory
devices (SwitchBot, temperature, bottom camera).
4. Purge dead RPyC references
Stale comments/handling from the old RPyC transfer path:
gently/hardware/dispim/devices/acquisition.py:216gently/hardware/dispim/plans/calibration.py:524Scope guard (deliberately deferred)
There is exactly one hardware plugin today; twophoton is aspirational. To avoid
abstracting the wrong joints from a sample size of one: extract only the obviously
generic plumbing now (1, 2, 4). Defer a "universal" device-layer abstraction until a
real second hardware exists to validate the seams (rule of three).