Skip to content

Device layer: extract hardware-agnostic BaseDeviceLayer + shared HTTP contract (split diSPIM monolith) #50

Description

@subindevs

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).

Metadata

Metadata

Assignees

Labels

architectureSystem architecturehardwareHardware/device relatedrefactorCode refactoring

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions