Skip to content

Add thermocycling capability and Opentrons vendor module#959

Open
rickwierenga wants to merge 9 commits intov1b1from
thermocycling-capability-v2
Open

Add thermocycling capability and Opentrons vendor module#959
rickwierenga wants to merge 9 commits intov1b1from
thermocycling-capability-v2

Conversation

@rickwierenga
Copy link
Member

Summary

  • Add pylabrobot/capabilities/thermocycling/ with thin ThermocyclingBackend (lid control, protocol execution, profile progress only — no temperature methods)
  • ThermocyclingCapability composes with block/lid TemperatureControlCapability instances
  • Own copies of Step/Stage/Protocol data types; translation functions in legacy standard.py
  • Legacy Thermocycler frontend delegates to capabilities via three adapters (_BlockTempAdapter, _LidTempAdapter, _ThermocyclingAdapter)
  • pylabrobot/opentrons/ vendor module with driver + 3 capability backends pattern:
    • OpentronsThermocyclerDriver — single class for all OT HTTP API calls
    • OpentronsBlockBackend, OpentronsLidBackend, OpentronsThermocyclingBackend
    • OpentronsThermocyclerV1 and V2 device classes
  • Legacy opentrons_backend.py delegates to new module

Usage (new API)

tc = OpentronsThermocyclerV1(name="tc", opentrons_id="...")
await tc.setup()

# Ad-hoc temperature control
await tc.block.set_temperature(95.0)
await tc.lid.set_temperature(105.0)

# Protocol execution
await tc.thermocycling.run_pcr_profile(
  denaturation_temp=[95.0], denaturation_time=30,
  annealing_temp=[55.0], annealing_time=30,
  extension_temp=[72.0], extension_time=60,
  num_cycles=30, block_max_volume=50,
  lid_temperature=105.0,
)
await tc.thermocycling.wait_for_profile_completion()

Test plan

  • All 4 legacy thermocycler tests pass
  • All imports verified (new + legacy)
  • Pre-commit hooks pass
  • CI tests pass

🤖 Generated with Claude Code

rickwierenga and others added 2 commits March 23, 2026 16:08
Capability:
- ThermocyclingBackend(DeviceBackend) — thin: lid control, protocol
  execution, and profile progress queries only. Block/lid temperature
  handled by separate TemperatureControllerBackend instances.
- ThermocyclingCapability composes with block/lid TemperatureControlCapability
- Own copies of Step/Stage/Protocol data types
- run_pcr_profile convenience method

Legacy:
- Translation functions (protocol_to_new, protocol_from_new) in legacy standard.py
- Three adapters in legacy thermocycler.py: _BlockTempAdapter,
  _LidTempAdapter, _ThermocyclingAdapter — wrap legacy ThermocyclerBackend
  for the new capability interfaces
- Legacy Thermocycler frontend delegates to capabilities via adapters
- All 4 legacy tests pass

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- OpentronsThermocyclerDriver: single class for all OT HTTP API calls
- Three capability backends backed by the driver:
  - OpentronsBlockBackend (TemperatureControllerBackend)
  - OpentronsLidBackend (TemperatureControllerBackend)
  - OpentronsThermocyclingBackend (ThermocyclingBackend)
- OpentronsThermocyclerV1 and V2 device classes with self._driver
- Legacy opentrons_backend.py delegates to new module via driver

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@rickwierenga rickwierenga changed the base branch from main to v1b1 March 23, 2026 23:13
rickwierenga and others added 7 commits March 23, 2026 16:45
- ThermoFisherThermocyclerDriver: single class for all SCPI I/O, auth,
  block discovery, power, temperature control, protocol execution
- Three capability backends per block:
  - ThermoFisherBlockBackend (TemperatureControllerBackend)
  - ThermoFisherLidBackend (TemperatureControllerBackend)
  - ThermoFisherThermocyclingBackend (ThermocyclingBackend)
- ThermoFisherThermocycler device with factory classmethods:
  proflex_single_block (1 block/6 zones), proflex_three_block (3 blocks/2 zones),
  atc (1 block/3 zones + lid control)
- Each block gets its own ThermocyclingCapability — run 3 PCR protocols simultaneously
- Legacy ThermoFisherThermocyclerBackend gutted to thin adapter (~275 lines, was ~1050)
- All 7 legacy tests pass

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- ThermoFisherThermocyclerDriver now extends DeviceBackend — passed
  directly to Device.__init__, no first_tc_backend hack
- Remove _supports_lid_control from device class (backend concern only)
- Split factory functions into separate files:
  - proflex.py: ProFlexSingleBlock(), ProFlexThreeBlock()
  - atc.py: ATC()
- Simplify _capabilities list construction

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- ODTCDriver(DeviceBackend): SiLA communication, setup/stop, sensor reading
- ODTCBlockBackend: block temperature control via PreMethod
- ODTCLidBackend: lid temperature control (coupled with block via PreMethod)
- ODTCThermocyclingBackend: protocol execution, lid open/close
- ODTC device class with block, lid, and thermocycling capabilities
- Legacy ExperimentalODTCBackend delegates to new module

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Split pylabrobot/thermo_fisher/thermocycler.py into:
- thermocyclers/driver.py — raw SCPI IO, auth, block discovery, power
- thermocyclers/block_backend.py — per-block temp control via send_command
- thermocyclers/lid_backend.py — per-block lid temp control via send_command
- thermocyclers/thermocycling_backend.py — protocol execution, run progress
- thermocyclers/thermocycler.py — device class
- thermocyclers/utils.py — XML/SCPI helpers, RunProgress
- thermocyclers/proflex.py, atc.py — factory functions

Backends call driver.send_command() directly — driver is pure IO layer.
Backward-compat shim at thermocycler.py re-exports from package.
All 3 legacy proflex tests pass.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- OT legacy backend: now delegates to new driver/backend (was self-contained)
- OT tests: updated patch targets to new module location
- TF legacy backend: delegates to per-block backends via lazy cache
- Move check_run_exists, create_run, get_log_by_runname,
  get_elapsed_run_time_from_log to TF driver (device-level, not per-block)
- All 19 legacy tests pass

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix empty backward compat shims (thermo_fisher/atc.py, proflex.py)
- Make OT driver a DeviceBackend (consistent with TF)
- OT device classes now pass driver to Device.__init__()
- Remove duplicate deactivate calls from OT thermocycling backend stop()
- Move dynamic imports to module level (ODTC legacy, thermocycler frontend)
- All 19 tests pass

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant