opentrons 8.6.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of opentrons might be problematic. Click here for more details.

Files changed (601) hide show
  1. opentrons/__init__.py +150 -0
  2. opentrons/_version.py +34 -0
  3. opentrons/calibration_storage/__init__.py +54 -0
  4. opentrons/calibration_storage/deck_configuration.py +62 -0
  5. opentrons/calibration_storage/encoder_decoder.py +31 -0
  6. opentrons/calibration_storage/file_operators.py +142 -0
  7. opentrons/calibration_storage/helpers.py +103 -0
  8. opentrons/calibration_storage/ot2/__init__.py +34 -0
  9. opentrons/calibration_storage/ot2/deck_attitude.py +85 -0
  10. opentrons/calibration_storage/ot2/mark_bad_calibration.py +27 -0
  11. opentrons/calibration_storage/ot2/models/__init__.py +0 -0
  12. opentrons/calibration_storage/ot2/models/v1.py +149 -0
  13. opentrons/calibration_storage/ot2/pipette_offset.py +129 -0
  14. opentrons/calibration_storage/ot2/tip_length.py +281 -0
  15. opentrons/calibration_storage/ot3/__init__.py +31 -0
  16. opentrons/calibration_storage/ot3/deck_attitude.py +83 -0
  17. opentrons/calibration_storage/ot3/gripper_offset.py +156 -0
  18. opentrons/calibration_storage/ot3/models/__init__.py +0 -0
  19. opentrons/calibration_storage/ot3/models/v1.py +122 -0
  20. opentrons/calibration_storage/ot3/module_offset.py +138 -0
  21. opentrons/calibration_storage/ot3/pipette_offset.py +95 -0
  22. opentrons/calibration_storage/types.py +45 -0
  23. opentrons/cli/__init__.py +21 -0
  24. opentrons/cli/__main__.py +5 -0
  25. opentrons/cli/analyze.py +557 -0
  26. opentrons/config/__init__.py +631 -0
  27. opentrons/config/advanced_settings.py +871 -0
  28. opentrons/config/defaults_ot2.py +214 -0
  29. opentrons/config/defaults_ot3.py +499 -0
  30. opentrons/config/feature_flags.py +86 -0
  31. opentrons/config/gripper_config.py +55 -0
  32. opentrons/config/reset.py +203 -0
  33. opentrons/config/robot_configs.py +187 -0
  34. opentrons/config/types.py +183 -0
  35. opentrons/drivers/__init__.py +0 -0
  36. opentrons/drivers/absorbance_reader/__init__.py +11 -0
  37. opentrons/drivers/absorbance_reader/abstract.py +72 -0
  38. opentrons/drivers/absorbance_reader/async_byonoy.py +352 -0
  39. opentrons/drivers/absorbance_reader/driver.py +81 -0
  40. opentrons/drivers/absorbance_reader/hid_protocol.py +161 -0
  41. opentrons/drivers/absorbance_reader/simulator.py +84 -0
  42. opentrons/drivers/asyncio/__init__.py +0 -0
  43. opentrons/drivers/asyncio/communication/__init__.py +22 -0
  44. opentrons/drivers/asyncio/communication/async_serial.py +187 -0
  45. opentrons/drivers/asyncio/communication/errors.py +88 -0
  46. opentrons/drivers/asyncio/communication/serial_connection.py +557 -0
  47. opentrons/drivers/command_builder.py +102 -0
  48. opentrons/drivers/flex_stacker/__init__.py +13 -0
  49. opentrons/drivers/flex_stacker/abstract.py +214 -0
  50. opentrons/drivers/flex_stacker/driver.py +768 -0
  51. opentrons/drivers/flex_stacker/errors.py +68 -0
  52. opentrons/drivers/flex_stacker/simulator.py +309 -0
  53. opentrons/drivers/flex_stacker/types.py +367 -0
  54. opentrons/drivers/flex_stacker/utils.py +19 -0
  55. opentrons/drivers/heater_shaker/__init__.py +5 -0
  56. opentrons/drivers/heater_shaker/abstract.py +76 -0
  57. opentrons/drivers/heater_shaker/driver.py +204 -0
  58. opentrons/drivers/heater_shaker/simulator.py +94 -0
  59. opentrons/drivers/mag_deck/__init__.py +6 -0
  60. opentrons/drivers/mag_deck/abstract.py +44 -0
  61. opentrons/drivers/mag_deck/driver.py +208 -0
  62. opentrons/drivers/mag_deck/simulator.py +63 -0
  63. opentrons/drivers/rpi_drivers/__init__.py +33 -0
  64. opentrons/drivers/rpi_drivers/dev_types.py +94 -0
  65. opentrons/drivers/rpi_drivers/gpio.py +282 -0
  66. opentrons/drivers/rpi_drivers/gpio_simulator.py +127 -0
  67. opentrons/drivers/rpi_drivers/interfaces.py +15 -0
  68. opentrons/drivers/rpi_drivers/types.py +364 -0
  69. opentrons/drivers/rpi_drivers/usb.py +102 -0
  70. opentrons/drivers/rpi_drivers/usb_simulator.py +22 -0
  71. opentrons/drivers/serial_communication.py +151 -0
  72. opentrons/drivers/smoothie_drivers/__init__.py +4 -0
  73. opentrons/drivers/smoothie_drivers/connection.py +51 -0
  74. opentrons/drivers/smoothie_drivers/constants.py +121 -0
  75. opentrons/drivers/smoothie_drivers/driver_3_0.py +1933 -0
  76. opentrons/drivers/smoothie_drivers/errors.py +49 -0
  77. opentrons/drivers/smoothie_drivers/parse_utils.py +143 -0
  78. opentrons/drivers/smoothie_drivers/simulator.py +99 -0
  79. opentrons/drivers/smoothie_drivers/types.py +16 -0
  80. opentrons/drivers/temp_deck/__init__.py +10 -0
  81. opentrons/drivers/temp_deck/abstract.py +54 -0
  82. opentrons/drivers/temp_deck/driver.py +197 -0
  83. opentrons/drivers/temp_deck/simulator.py +57 -0
  84. opentrons/drivers/thermocycler/__init__.py +12 -0
  85. opentrons/drivers/thermocycler/abstract.py +99 -0
  86. opentrons/drivers/thermocycler/driver.py +395 -0
  87. opentrons/drivers/thermocycler/simulator.py +126 -0
  88. opentrons/drivers/types.py +107 -0
  89. opentrons/drivers/utils.py +222 -0
  90. opentrons/execute.py +742 -0
  91. opentrons/hardware_control/__init__.py +65 -0
  92. opentrons/hardware_control/__main__.py +77 -0
  93. opentrons/hardware_control/adapters.py +98 -0
  94. opentrons/hardware_control/api.py +1347 -0
  95. opentrons/hardware_control/backends/__init__.py +7 -0
  96. opentrons/hardware_control/backends/controller.py +400 -0
  97. opentrons/hardware_control/backends/errors.py +9 -0
  98. opentrons/hardware_control/backends/estop_state.py +164 -0
  99. opentrons/hardware_control/backends/flex_protocol.py +497 -0
  100. opentrons/hardware_control/backends/ot3controller.py +1930 -0
  101. opentrons/hardware_control/backends/ot3simulator.py +900 -0
  102. opentrons/hardware_control/backends/ot3utils.py +664 -0
  103. opentrons/hardware_control/backends/simulator.py +442 -0
  104. opentrons/hardware_control/backends/status_bar_state.py +240 -0
  105. opentrons/hardware_control/backends/subsystem_manager.py +431 -0
  106. opentrons/hardware_control/backends/tip_presence_manager.py +173 -0
  107. opentrons/hardware_control/backends/types.py +14 -0
  108. opentrons/hardware_control/constants.py +6 -0
  109. opentrons/hardware_control/dev_types.py +125 -0
  110. opentrons/hardware_control/emulation/__init__.py +0 -0
  111. opentrons/hardware_control/emulation/abstract_emulator.py +21 -0
  112. opentrons/hardware_control/emulation/app.py +56 -0
  113. opentrons/hardware_control/emulation/connection_handler.py +38 -0
  114. opentrons/hardware_control/emulation/heater_shaker.py +150 -0
  115. opentrons/hardware_control/emulation/magdeck.py +60 -0
  116. opentrons/hardware_control/emulation/module_server/__init__.py +8 -0
  117. opentrons/hardware_control/emulation/module_server/client.py +78 -0
  118. opentrons/hardware_control/emulation/module_server/helpers.py +130 -0
  119. opentrons/hardware_control/emulation/module_server/models.py +31 -0
  120. opentrons/hardware_control/emulation/module_server/server.py +110 -0
  121. opentrons/hardware_control/emulation/parser.py +74 -0
  122. opentrons/hardware_control/emulation/proxy.py +241 -0
  123. opentrons/hardware_control/emulation/run_emulator.py +68 -0
  124. opentrons/hardware_control/emulation/scripts/__init__.py +0 -0
  125. opentrons/hardware_control/emulation/scripts/run_app.py +54 -0
  126. opentrons/hardware_control/emulation/scripts/run_module_emulator.py +72 -0
  127. opentrons/hardware_control/emulation/scripts/run_smoothie.py +37 -0
  128. opentrons/hardware_control/emulation/settings.py +119 -0
  129. opentrons/hardware_control/emulation/simulations.py +133 -0
  130. opentrons/hardware_control/emulation/smoothie.py +192 -0
  131. opentrons/hardware_control/emulation/tempdeck.py +69 -0
  132. opentrons/hardware_control/emulation/thermocycler.py +128 -0
  133. opentrons/hardware_control/emulation/types.py +10 -0
  134. opentrons/hardware_control/emulation/util.py +38 -0
  135. opentrons/hardware_control/errors.py +43 -0
  136. opentrons/hardware_control/execution_manager.py +164 -0
  137. opentrons/hardware_control/instruments/__init__.py +5 -0
  138. opentrons/hardware_control/instruments/instrument_abc.py +39 -0
  139. opentrons/hardware_control/instruments/ot2/__init__.py +0 -0
  140. opentrons/hardware_control/instruments/ot2/instrument_calibration.py +152 -0
  141. opentrons/hardware_control/instruments/ot2/pipette.py +777 -0
  142. opentrons/hardware_control/instruments/ot2/pipette_handler.py +995 -0
  143. opentrons/hardware_control/instruments/ot3/__init__.py +0 -0
  144. opentrons/hardware_control/instruments/ot3/gripper.py +420 -0
  145. opentrons/hardware_control/instruments/ot3/gripper_handler.py +173 -0
  146. opentrons/hardware_control/instruments/ot3/instrument_calibration.py +214 -0
  147. opentrons/hardware_control/instruments/ot3/pipette.py +858 -0
  148. opentrons/hardware_control/instruments/ot3/pipette_handler.py +1030 -0
  149. opentrons/hardware_control/module_control.py +332 -0
  150. opentrons/hardware_control/modules/__init__.py +69 -0
  151. opentrons/hardware_control/modules/absorbance_reader.py +373 -0
  152. opentrons/hardware_control/modules/errors.py +7 -0
  153. opentrons/hardware_control/modules/flex_stacker.py +948 -0
  154. opentrons/hardware_control/modules/heater_shaker.py +426 -0
  155. opentrons/hardware_control/modules/lid_temp_status.py +35 -0
  156. opentrons/hardware_control/modules/magdeck.py +233 -0
  157. opentrons/hardware_control/modules/mod_abc.py +245 -0
  158. opentrons/hardware_control/modules/module_calibration.py +93 -0
  159. opentrons/hardware_control/modules/plate_temp_status.py +61 -0
  160. opentrons/hardware_control/modules/tempdeck.py +299 -0
  161. opentrons/hardware_control/modules/thermocycler.py +731 -0
  162. opentrons/hardware_control/modules/types.py +417 -0
  163. opentrons/hardware_control/modules/update.py +255 -0
  164. opentrons/hardware_control/modules/utils.py +73 -0
  165. opentrons/hardware_control/motion_utilities.py +318 -0
  166. opentrons/hardware_control/nozzle_manager.py +422 -0
  167. opentrons/hardware_control/ot3_calibration.py +1171 -0
  168. opentrons/hardware_control/ot3api.py +3227 -0
  169. opentrons/hardware_control/pause_manager.py +31 -0
  170. opentrons/hardware_control/poller.py +112 -0
  171. opentrons/hardware_control/protocols/__init__.py +106 -0
  172. opentrons/hardware_control/protocols/asyncio_configurable.py +11 -0
  173. opentrons/hardware_control/protocols/calibratable.py +45 -0
  174. opentrons/hardware_control/protocols/chassis_accessory_manager.py +90 -0
  175. opentrons/hardware_control/protocols/configurable.py +48 -0
  176. opentrons/hardware_control/protocols/event_sourcer.py +18 -0
  177. opentrons/hardware_control/protocols/execution_controllable.py +33 -0
  178. opentrons/hardware_control/protocols/flex_calibratable.py +96 -0
  179. opentrons/hardware_control/protocols/flex_instrument_configurer.py +52 -0
  180. opentrons/hardware_control/protocols/gripper_controller.py +55 -0
  181. opentrons/hardware_control/protocols/hardware_manager.py +51 -0
  182. opentrons/hardware_control/protocols/identifiable.py +16 -0
  183. opentrons/hardware_control/protocols/instrument_configurer.py +206 -0
  184. opentrons/hardware_control/protocols/liquid_handler.py +266 -0
  185. opentrons/hardware_control/protocols/module_provider.py +16 -0
  186. opentrons/hardware_control/protocols/motion_controller.py +243 -0
  187. opentrons/hardware_control/protocols/position_estimator.py +45 -0
  188. opentrons/hardware_control/protocols/simulatable.py +10 -0
  189. opentrons/hardware_control/protocols/stoppable.py +9 -0
  190. opentrons/hardware_control/protocols/types.py +27 -0
  191. opentrons/hardware_control/robot_calibration.py +224 -0
  192. opentrons/hardware_control/scripts/README.md +28 -0
  193. opentrons/hardware_control/scripts/__init__.py +1 -0
  194. opentrons/hardware_control/scripts/gripper_control.py +208 -0
  195. opentrons/hardware_control/scripts/ot3gripper +7 -0
  196. opentrons/hardware_control/scripts/ot3repl +7 -0
  197. opentrons/hardware_control/scripts/repl.py +187 -0
  198. opentrons/hardware_control/scripts/tc_control.py +97 -0
  199. opentrons/hardware_control/scripts/update_module_fw.py +274 -0
  200. opentrons/hardware_control/simulator_setup.py +260 -0
  201. opentrons/hardware_control/thread_manager.py +431 -0
  202. opentrons/hardware_control/threaded_async_lock.py +97 -0
  203. opentrons/hardware_control/types.py +792 -0
  204. opentrons/hardware_control/util.py +234 -0
  205. opentrons/legacy_broker.py +53 -0
  206. opentrons/legacy_commands/__init__.py +1 -0
  207. opentrons/legacy_commands/commands.py +483 -0
  208. opentrons/legacy_commands/helpers.py +153 -0
  209. opentrons/legacy_commands/module_commands.py +276 -0
  210. opentrons/legacy_commands/protocol_commands.py +54 -0
  211. opentrons/legacy_commands/publisher.py +155 -0
  212. opentrons/legacy_commands/robot_commands.py +51 -0
  213. opentrons/legacy_commands/types.py +1186 -0
  214. opentrons/motion_planning/__init__.py +32 -0
  215. opentrons/motion_planning/adjacent_slots_getters.py +168 -0
  216. opentrons/motion_planning/deck_conflict.py +501 -0
  217. opentrons/motion_planning/errors.py +35 -0
  218. opentrons/motion_planning/types.py +42 -0
  219. opentrons/motion_planning/waypoints.py +218 -0
  220. opentrons/ordered_set.py +138 -0
  221. opentrons/protocol_api/__init__.py +105 -0
  222. opentrons/protocol_api/_liquid.py +157 -0
  223. opentrons/protocol_api/_liquid_properties.py +814 -0
  224. opentrons/protocol_api/_nozzle_layout.py +31 -0
  225. opentrons/protocol_api/_parameter_context.py +300 -0
  226. opentrons/protocol_api/_parameters.py +31 -0
  227. opentrons/protocol_api/_transfer_liquid_validation.py +108 -0
  228. opentrons/protocol_api/_types.py +43 -0
  229. opentrons/protocol_api/config.py +23 -0
  230. opentrons/protocol_api/core/__init__.py +23 -0
  231. opentrons/protocol_api/core/common.py +33 -0
  232. opentrons/protocol_api/core/core_map.py +74 -0
  233. opentrons/protocol_api/core/engine/__init__.py +22 -0
  234. opentrons/protocol_api/core/engine/_default_labware_versions.py +179 -0
  235. opentrons/protocol_api/core/engine/deck_conflict.py +400 -0
  236. opentrons/protocol_api/core/engine/exceptions.py +19 -0
  237. opentrons/protocol_api/core/engine/instrument.py +2391 -0
  238. opentrons/protocol_api/core/engine/labware.py +238 -0
  239. opentrons/protocol_api/core/engine/load_labware_params.py +73 -0
  240. opentrons/protocol_api/core/engine/module_core.py +1027 -0
  241. opentrons/protocol_api/core/engine/overlap_versions.py +20 -0
  242. opentrons/protocol_api/core/engine/pipette_movement_conflict.py +358 -0
  243. opentrons/protocol_api/core/engine/point_calculations.py +64 -0
  244. opentrons/protocol_api/core/engine/protocol.py +1153 -0
  245. opentrons/protocol_api/core/engine/robot.py +139 -0
  246. opentrons/protocol_api/core/engine/stringify.py +74 -0
  247. opentrons/protocol_api/core/engine/transfer_components_executor.py +1006 -0
  248. opentrons/protocol_api/core/engine/well.py +241 -0
  249. opentrons/protocol_api/core/instrument.py +459 -0
  250. opentrons/protocol_api/core/labware.py +151 -0
  251. opentrons/protocol_api/core/legacy/__init__.py +11 -0
  252. opentrons/protocol_api/core/legacy/_labware_geometry.py +37 -0
  253. opentrons/protocol_api/core/legacy/deck.py +369 -0
  254. opentrons/protocol_api/core/legacy/labware_offset_provider.py +108 -0
  255. opentrons/protocol_api/core/legacy/legacy_instrument_core.py +709 -0
  256. opentrons/protocol_api/core/legacy/legacy_labware_core.py +235 -0
  257. opentrons/protocol_api/core/legacy/legacy_module_core.py +592 -0
  258. opentrons/protocol_api/core/legacy/legacy_protocol_core.py +612 -0
  259. opentrons/protocol_api/core/legacy/legacy_well_core.py +162 -0
  260. opentrons/protocol_api/core/legacy/load_info.py +67 -0
  261. opentrons/protocol_api/core/legacy/module_geometry.py +547 -0
  262. opentrons/protocol_api/core/legacy/well_geometry.py +148 -0
  263. opentrons/protocol_api/core/legacy_simulator/__init__.py +16 -0
  264. opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +624 -0
  265. opentrons/protocol_api/core/legacy_simulator/legacy_protocol_core.py +85 -0
  266. opentrons/protocol_api/core/module.py +484 -0
  267. opentrons/protocol_api/core/protocol.py +311 -0
  268. opentrons/protocol_api/core/robot.py +51 -0
  269. opentrons/protocol_api/core/well.py +116 -0
  270. opentrons/protocol_api/core/well_grid.py +45 -0
  271. opentrons/protocol_api/create_protocol_context.py +177 -0
  272. opentrons/protocol_api/deck.py +223 -0
  273. opentrons/protocol_api/disposal_locations.py +244 -0
  274. opentrons/protocol_api/instrument_context.py +3272 -0
  275. opentrons/protocol_api/labware.py +1579 -0
  276. opentrons/protocol_api/module_contexts.py +1447 -0
  277. opentrons/protocol_api/module_validation_and_errors.py +61 -0
  278. opentrons/protocol_api/protocol_context.py +1688 -0
  279. opentrons/protocol_api/robot_context.py +303 -0
  280. opentrons/protocol_api/validation.py +761 -0
  281. opentrons/protocol_engine/__init__.py +155 -0
  282. opentrons/protocol_engine/actions/__init__.py +65 -0
  283. opentrons/protocol_engine/actions/action_dispatcher.py +30 -0
  284. opentrons/protocol_engine/actions/action_handler.py +13 -0
  285. opentrons/protocol_engine/actions/actions.py +302 -0
  286. opentrons/protocol_engine/actions/get_state_update.py +38 -0
  287. opentrons/protocol_engine/clients/__init__.py +5 -0
  288. opentrons/protocol_engine/clients/sync_client.py +174 -0
  289. opentrons/protocol_engine/clients/transports.py +197 -0
  290. opentrons/protocol_engine/commands/__init__.py +757 -0
  291. opentrons/protocol_engine/commands/absorbance_reader/__init__.py +61 -0
  292. opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +154 -0
  293. opentrons/protocol_engine/commands/absorbance_reader/common.py +6 -0
  294. opentrons/protocol_engine/commands/absorbance_reader/initialize.py +151 -0
  295. opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +154 -0
  296. opentrons/protocol_engine/commands/absorbance_reader/read.py +226 -0
  297. opentrons/protocol_engine/commands/air_gap_in_place.py +162 -0
  298. opentrons/protocol_engine/commands/aspirate.py +244 -0
  299. opentrons/protocol_engine/commands/aspirate_in_place.py +184 -0
  300. opentrons/protocol_engine/commands/aspirate_while_tracking.py +211 -0
  301. opentrons/protocol_engine/commands/blow_out.py +146 -0
  302. opentrons/protocol_engine/commands/blow_out_in_place.py +119 -0
  303. opentrons/protocol_engine/commands/calibration/__init__.py +60 -0
  304. opentrons/protocol_engine/commands/calibration/calibrate_gripper.py +166 -0
  305. opentrons/protocol_engine/commands/calibration/calibrate_module.py +117 -0
  306. opentrons/protocol_engine/commands/calibration/calibrate_pipette.py +96 -0
  307. opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py +156 -0
  308. opentrons/protocol_engine/commands/command.py +308 -0
  309. opentrons/protocol_engine/commands/command_unions.py +974 -0
  310. opentrons/protocol_engine/commands/comment.py +57 -0
  311. opentrons/protocol_engine/commands/configure_for_volume.py +108 -0
  312. opentrons/protocol_engine/commands/configure_nozzle_layout.py +115 -0
  313. opentrons/protocol_engine/commands/custom.py +67 -0
  314. opentrons/protocol_engine/commands/dispense.py +194 -0
  315. opentrons/protocol_engine/commands/dispense_in_place.py +179 -0
  316. opentrons/protocol_engine/commands/dispense_while_tracking.py +204 -0
  317. opentrons/protocol_engine/commands/drop_tip.py +232 -0
  318. opentrons/protocol_engine/commands/drop_tip_in_place.py +205 -0
  319. opentrons/protocol_engine/commands/flex_stacker/__init__.py +64 -0
  320. opentrons/protocol_engine/commands/flex_stacker/common.py +900 -0
  321. opentrons/protocol_engine/commands/flex_stacker/empty.py +293 -0
  322. opentrons/protocol_engine/commands/flex_stacker/fill.py +281 -0
  323. opentrons/protocol_engine/commands/flex_stacker/retrieve.py +339 -0
  324. opentrons/protocol_engine/commands/flex_stacker/set_stored_labware.py +328 -0
  325. opentrons/protocol_engine/commands/flex_stacker/store.py +339 -0
  326. opentrons/protocol_engine/commands/generate_command_schema.py +61 -0
  327. opentrons/protocol_engine/commands/get_next_tip.py +134 -0
  328. opentrons/protocol_engine/commands/get_tip_presence.py +87 -0
  329. opentrons/protocol_engine/commands/hash_command_params.py +38 -0
  330. opentrons/protocol_engine/commands/heater_shaker/__init__.py +102 -0
  331. opentrons/protocol_engine/commands/heater_shaker/close_labware_latch.py +83 -0
  332. opentrons/protocol_engine/commands/heater_shaker/deactivate_heater.py +82 -0
  333. opentrons/protocol_engine/commands/heater_shaker/deactivate_shaker.py +84 -0
  334. opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py +110 -0
  335. opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +125 -0
  336. opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +90 -0
  337. opentrons/protocol_engine/commands/heater_shaker/wait_for_temperature.py +102 -0
  338. opentrons/protocol_engine/commands/home.py +100 -0
  339. opentrons/protocol_engine/commands/identify_module.py +86 -0
  340. opentrons/protocol_engine/commands/labware_handling_common.py +29 -0
  341. opentrons/protocol_engine/commands/liquid_probe.py +464 -0
  342. opentrons/protocol_engine/commands/load_labware.py +210 -0
  343. opentrons/protocol_engine/commands/load_lid.py +154 -0
  344. opentrons/protocol_engine/commands/load_lid_stack.py +272 -0
  345. opentrons/protocol_engine/commands/load_liquid.py +95 -0
  346. opentrons/protocol_engine/commands/load_liquid_class.py +144 -0
  347. opentrons/protocol_engine/commands/load_module.py +223 -0
  348. opentrons/protocol_engine/commands/load_pipette.py +167 -0
  349. opentrons/protocol_engine/commands/magnetic_module/__init__.py +32 -0
  350. opentrons/protocol_engine/commands/magnetic_module/disengage.py +97 -0
  351. opentrons/protocol_engine/commands/magnetic_module/engage.py +119 -0
  352. opentrons/protocol_engine/commands/move_labware.py +546 -0
  353. opentrons/protocol_engine/commands/move_relative.py +102 -0
  354. opentrons/protocol_engine/commands/move_to_addressable_area.py +176 -0
  355. opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py +198 -0
  356. opentrons/protocol_engine/commands/move_to_coordinates.py +107 -0
  357. opentrons/protocol_engine/commands/move_to_well.py +119 -0
  358. opentrons/protocol_engine/commands/movement_common.py +338 -0
  359. opentrons/protocol_engine/commands/pick_up_tip.py +241 -0
  360. opentrons/protocol_engine/commands/pipetting_common.py +443 -0
  361. opentrons/protocol_engine/commands/prepare_to_aspirate.py +121 -0
  362. opentrons/protocol_engine/commands/pressure_dispense.py +155 -0
  363. opentrons/protocol_engine/commands/reload_labware.py +90 -0
  364. opentrons/protocol_engine/commands/retract_axis.py +75 -0
  365. opentrons/protocol_engine/commands/robot/__init__.py +70 -0
  366. opentrons/protocol_engine/commands/robot/close_gripper_jaw.py +96 -0
  367. opentrons/protocol_engine/commands/robot/common.py +18 -0
  368. opentrons/protocol_engine/commands/robot/move_axes_relative.py +101 -0
  369. opentrons/protocol_engine/commands/robot/move_axes_to.py +100 -0
  370. opentrons/protocol_engine/commands/robot/move_to.py +94 -0
  371. opentrons/protocol_engine/commands/robot/open_gripper_jaw.py +86 -0
  372. opentrons/protocol_engine/commands/save_position.py +109 -0
  373. opentrons/protocol_engine/commands/seal_pipette_to_tip.py +353 -0
  374. opentrons/protocol_engine/commands/set_rail_lights.py +67 -0
  375. opentrons/protocol_engine/commands/set_status_bar.py +89 -0
  376. opentrons/protocol_engine/commands/temperature_module/__init__.py +46 -0
  377. opentrons/protocol_engine/commands/temperature_module/deactivate.py +86 -0
  378. opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +97 -0
  379. opentrons/protocol_engine/commands/temperature_module/wait_for_temperature.py +104 -0
  380. opentrons/protocol_engine/commands/thermocycler/__init__.py +152 -0
  381. opentrons/protocol_engine/commands/thermocycler/close_lid.py +87 -0
  382. opentrons/protocol_engine/commands/thermocycler/deactivate_block.py +80 -0
  383. opentrons/protocol_engine/commands/thermocycler/deactivate_lid.py +80 -0
  384. opentrons/protocol_engine/commands/thermocycler/open_lid.py +87 -0
  385. opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +171 -0
  386. opentrons/protocol_engine/commands/thermocycler/run_profile.py +124 -0
  387. opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +140 -0
  388. opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +100 -0
  389. opentrons/protocol_engine/commands/thermocycler/wait_for_block_temperature.py +93 -0
  390. opentrons/protocol_engine/commands/thermocycler/wait_for_lid_temperature.py +89 -0
  391. opentrons/protocol_engine/commands/touch_tip.py +189 -0
  392. opentrons/protocol_engine/commands/unsafe/__init__.py +161 -0
  393. opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +100 -0
  394. opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +121 -0
  395. opentrons/protocol_engine/commands/unsafe/unsafe_engage_axes.py +82 -0
  396. opentrons/protocol_engine/commands/unsafe/unsafe_place_labware.py +208 -0
  397. opentrons/protocol_engine/commands/unsafe/unsafe_stacker_close_latch.py +94 -0
  398. opentrons/protocol_engine/commands/unsafe/unsafe_stacker_manual_retrieve.py +295 -0
  399. opentrons/protocol_engine/commands/unsafe/unsafe_stacker_open_latch.py +91 -0
  400. opentrons/protocol_engine/commands/unsafe/unsafe_stacker_prepare_shuttle.py +136 -0
  401. opentrons/protocol_engine/commands/unsafe/unsafe_ungrip_labware.py +77 -0
  402. opentrons/protocol_engine/commands/unsafe/update_position_estimators.py +90 -0
  403. opentrons/protocol_engine/commands/unseal_pipette_from_tip.py +153 -0
  404. opentrons/protocol_engine/commands/verify_tip_presence.py +100 -0
  405. opentrons/protocol_engine/commands/wait_for_duration.py +76 -0
  406. opentrons/protocol_engine/commands/wait_for_resume.py +75 -0
  407. opentrons/protocol_engine/create_protocol_engine.py +193 -0
  408. opentrons/protocol_engine/engine_support.py +28 -0
  409. opentrons/protocol_engine/error_recovery_policy.py +81 -0
  410. opentrons/protocol_engine/errors/__init__.py +191 -0
  411. opentrons/protocol_engine/errors/error_occurrence.py +182 -0
  412. opentrons/protocol_engine/errors/exceptions.py +1308 -0
  413. opentrons/protocol_engine/execution/__init__.py +50 -0
  414. opentrons/protocol_engine/execution/command_executor.py +216 -0
  415. opentrons/protocol_engine/execution/create_queue_worker.py +102 -0
  416. opentrons/protocol_engine/execution/door_watcher.py +119 -0
  417. opentrons/protocol_engine/execution/equipment.py +819 -0
  418. opentrons/protocol_engine/execution/error_recovery_hardware_state_synchronizer.py +101 -0
  419. opentrons/protocol_engine/execution/gantry_mover.py +686 -0
  420. opentrons/protocol_engine/execution/hardware_stopper.py +147 -0
  421. opentrons/protocol_engine/execution/heater_shaker_movement_flagger.py +207 -0
  422. opentrons/protocol_engine/execution/labware_movement.py +297 -0
  423. opentrons/protocol_engine/execution/movement.py +350 -0
  424. opentrons/protocol_engine/execution/pipetting.py +607 -0
  425. opentrons/protocol_engine/execution/queue_worker.py +86 -0
  426. opentrons/protocol_engine/execution/rail_lights.py +25 -0
  427. opentrons/protocol_engine/execution/run_control.py +33 -0
  428. opentrons/protocol_engine/execution/status_bar.py +34 -0
  429. opentrons/protocol_engine/execution/thermocycler_movement_flagger.py +188 -0
  430. opentrons/protocol_engine/execution/thermocycler_plate_lifter.py +81 -0
  431. opentrons/protocol_engine/execution/tip_handler.py +550 -0
  432. opentrons/protocol_engine/labware_offset_standardization.py +194 -0
  433. opentrons/protocol_engine/notes/__init__.py +17 -0
  434. opentrons/protocol_engine/notes/notes.py +59 -0
  435. opentrons/protocol_engine/plugins.py +104 -0
  436. opentrons/protocol_engine/protocol_engine.py +683 -0
  437. opentrons/protocol_engine/resources/__init__.py +26 -0
  438. opentrons/protocol_engine/resources/deck_configuration_provider.py +232 -0
  439. opentrons/protocol_engine/resources/deck_data_provider.py +94 -0
  440. opentrons/protocol_engine/resources/file_provider.py +161 -0
  441. opentrons/protocol_engine/resources/fixture_validation.py +68 -0
  442. opentrons/protocol_engine/resources/labware_data_provider.py +106 -0
  443. opentrons/protocol_engine/resources/labware_validation.py +73 -0
  444. opentrons/protocol_engine/resources/model_utils.py +32 -0
  445. opentrons/protocol_engine/resources/module_data_provider.py +44 -0
  446. opentrons/protocol_engine/resources/ot3_validation.py +21 -0
  447. opentrons/protocol_engine/resources/pipette_data_provider.py +379 -0
  448. opentrons/protocol_engine/slot_standardization.py +128 -0
  449. opentrons/protocol_engine/state/__init__.py +1 -0
  450. opentrons/protocol_engine/state/_abstract_store.py +27 -0
  451. opentrons/protocol_engine/state/_axis_aligned_bounding_box.py +50 -0
  452. opentrons/protocol_engine/state/_labware_origin_math.py +636 -0
  453. opentrons/protocol_engine/state/_move_types.py +83 -0
  454. opentrons/protocol_engine/state/_well_math.py +193 -0
  455. opentrons/protocol_engine/state/addressable_areas.py +699 -0
  456. opentrons/protocol_engine/state/command_history.py +309 -0
  457. opentrons/protocol_engine/state/commands.py +1164 -0
  458. opentrons/protocol_engine/state/config.py +39 -0
  459. opentrons/protocol_engine/state/files.py +57 -0
  460. opentrons/protocol_engine/state/fluid_stack.py +138 -0
  461. opentrons/protocol_engine/state/geometry.py +2408 -0
  462. opentrons/protocol_engine/state/inner_well_math_utils.py +548 -0
  463. opentrons/protocol_engine/state/labware.py +1432 -0
  464. opentrons/protocol_engine/state/liquid_classes.py +82 -0
  465. opentrons/protocol_engine/state/liquids.py +73 -0
  466. opentrons/protocol_engine/state/module_substates/__init__.py +45 -0
  467. opentrons/protocol_engine/state/module_substates/absorbance_reader_substate.py +35 -0
  468. opentrons/protocol_engine/state/module_substates/flex_stacker_substate.py +112 -0
  469. opentrons/protocol_engine/state/module_substates/heater_shaker_module_substate.py +115 -0
  470. opentrons/protocol_engine/state/module_substates/magnetic_block_substate.py +17 -0
  471. opentrons/protocol_engine/state/module_substates/magnetic_module_substate.py +65 -0
  472. opentrons/protocol_engine/state/module_substates/temperature_module_substate.py +67 -0
  473. opentrons/protocol_engine/state/module_substates/thermocycler_module_substate.py +163 -0
  474. opentrons/protocol_engine/state/modules.py +1515 -0
  475. opentrons/protocol_engine/state/motion.py +373 -0
  476. opentrons/protocol_engine/state/pipettes.py +905 -0
  477. opentrons/protocol_engine/state/state.py +421 -0
  478. opentrons/protocol_engine/state/state_summary.py +36 -0
  479. opentrons/protocol_engine/state/tips.py +420 -0
  480. opentrons/protocol_engine/state/update_types.py +904 -0
  481. opentrons/protocol_engine/state/wells.py +290 -0
  482. opentrons/protocol_engine/types/__init__.py +310 -0
  483. opentrons/protocol_engine/types/automatic_tip_selection.py +39 -0
  484. opentrons/protocol_engine/types/command_annotations.py +53 -0
  485. opentrons/protocol_engine/types/deck_configuration.py +81 -0
  486. opentrons/protocol_engine/types/execution.py +96 -0
  487. opentrons/protocol_engine/types/hardware_passthrough.py +25 -0
  488. opentrons/protocol_engine/types/instrument.py +47 -0
  489. opentrons/protocol_engine/types/instrument_sensors.py +47 -0
  490. opentrons/protocol_engine/types/labware.py +131 -0
  491. opentrons/protocol_engine/types/labware_movement.py +22 -0
  492. opentrons/protocol_engine/types/labware_offset_location.py +111 -0
  493. opentrons/protocol_engine/types/labware_offset_vector.py +16 -0
  494. opentrons/protocol_engine/types/liquid.py +40 -0
  495. opentrons/protocol_engine/types/liquid_class.py +59 -0
  496. opentrons/protocol_engine/types/liquid_handling.py +13 -0
  497. opentrons/protocol_engine/types/liquid_level_detection.py +191 -0
  498. opentrons/protocol_engine/types/location.py +194 -0
  499. opentrons/protocol_engine/types/module.py +310 -0
  500. opentrons/protocol_engine/types/partial_tip_configuration.py +76 -0
  501. opentrons/protocol_engine/types/run_time_parameters.py +133 -0
  502. opentrons/protocol_engine/types/tip.py +18 -0
  503. opentrons/protocol_engine/types/util.py +21 -0
  504. opentrons/protocol_engine/types/well_position.py +124 -0
  505. opentrons/protocol_reader/__init__.py +37 -0
  506. opentrons/protocol_reader/extract_labware_definitions.py +66 -0
  507. opentrons/protocol_reader/file_format_validator.py +152 -0
  508. opentrons/protocol_reader/file_hasher.py +27 -0
  509. opentrons/protocol_reader/file_identifier.py +284 -0
  510. opentrons/protocol_reader/file_reader_writer.py +90 -0
  511. opentrons/protocol_reader/input_file.py +16 -0
  512. opentrons/protocol_reader/protocol_files_invalid_error.py +6 -0
  513. opentrons/protocol_reader/protocol_reader.py +188 -0
  514. opentrons/protocol_reader/protocol_source.py +124 -0
  515. opentrons/protocol_reader/role_analyzer.py +86 -0
  516. opentrons/protocol_runner/__init__.py +26 -0
  517. opentrons/protocol_runner/create_simulating_orchestrator.py +118 -0
  518. opentrons/protocol_runner/json_file_reader.py +55 -0
  519. opentrons/protocol_runner/json_translator.py +314 -0
  520. opentrons/protocol_runner/legacy_command_mapper.py +852 -0
  521. opentrons/protocol_runner/legacy_context_plugin.py +116 -0
  522. opentrons/protocol_runner/protocol_runner.py +530 -0
  523. opentrons/protocol_runner/python_protocol_wrappers.py +179 -0
  524. opentrons/protocol_runner/run_orchestrator.py +496 -0
  525. opentrons/protocol_runner/task_queue.py +95 -0
  526. opentrons/protocols/__init__.py +6 -0
  527. opentrons/protocols/advanced_control/__init__.py +0 -0
  528. opentrons/protocols/advanced_control/common.py +38 -0
  529. opentrons/protocols/advanced_control/mix.py +60 -0
  530. opentrons/protocols/advanced_control/transfers/__init__.py +0 -0
  531. opentrons/protocols/advanced_control/transfers/common.py +180 -0
  532. opentrons/protocols/advanced_control/transfers/transfer.py +972 -0
  533. opentrons/protocols/advanced_control/transfers/transfer_liquid_utils.py +231 -0
  534. opentrons/protocols/api_support/__init__.py +0 -0
  535. opentrons/protocols/api_support/constants.py +8 -0
  536. opentrons/protocols/api_support/deck_type.py +110 -0
  537. opentrons/protocols/api_support/definitions.py +18 -0
  538. opentrons/protocols/api_support/instrument.py +151 -0
  539. opentrons/protocols/api_support/labware_like.py +233 -0
  540. opentrons/protocols/api_support/tip_tracker.py +175 -0
  541. opentrons/protocols/api_support/types.py +32 -0
  542. opentrons/protocols/api_support/util.py +403 -0
  543. opentrons/protocols/bundle.py +89 -0
  544. opentrons/protocols/duration/__init__.py +4 -0
  545. opentrons/protocols/duration/errors.py +5 -0
  546. opentrons/protocols/duration/estimator.py +628 -0
  547. opentrons/protocols/execution/__init__.py +0 -0
  548. opentrons/protocols/execution/dev_types.py +181 -0
  549. opentrons/protocols/execution/errors.py +40 -0
  550. opentrons/protocols/execution/execute.py +84 -0
  551. opentrons/protocols/execution/execute_json_v3.py +275 -0
  552. opentrons/protocols/execution/execute_json_v4.py +359 -0
  553. opentrons/protocols/execution/execute_json_v5.py +28 -0
  554. opentrons/protocols/execution/execute_python.py +169 -0
  555. opentrons/protocols/execution/json_dispatchers.py +87 -0
  556. opentrons/protocols/execution/types.py +7 -0
  557. opentrons/protocols/geometry/__init__.py +0 -0
  558. opentrons/protocols/geometry/planning.py +297 -0
  559. opentrons/protocols/labware.py +312 -0
  560. opentrons/protocols/models/__init__.py +0 -0
  561. opentrons/protocols/models/json_protocol.py +679 -0
  562. opentrons/protocols/parameters/__init__.py +0 -0
  563. opentrons/protocols/parameters/csv_parameter_definition.py +77 -0
  564. opentrons/protocols/parameters/csv_parameter_interface.py +96 -0
  565. opentrons/protocols/parameters/exceptions.py +34 -0
  566. opentrons/protocols/parameters/parameter_definition.py +272 -0
  567. opentrons/protocols/parameters/types.py +17 -0
  568. opentrons/protocols/parameters/validation.py +267 -0
  569. opentrons/protocols/parse.py +671 -0
  570. opentrons/protocols/types.py +159 -0
  571. opentrons/py.typed +0 -0
  572. opentrons/resources/scripts/lpc21isp +0 -0
  573. opentrons/resources/smoothie-edge-8414642.hex +23010 -0
  574. opentrons/simulate.py +1065 -0
  575. opentrons/system/__init__.py +6 -0
  576. opentrons/system/camera.py +51 -0
  577. opentrons/system/log_control.py +59 -0
  578. opentrons/system/nmcli.py +856 -0
  579. opentrons/system/resin.py +24 -0
  580. opentrons/system/smoothie_update.py +15 -0
  581. opentrons/system/wifi.py +204 -0
  582. opentrons/tools/__init__.py +0 -0
  583. opentrons/tools/args_handler.py +22 -0
  584. opentrons/tools/write_pipette_memory.py +157 -0
  585. opentrons/types.py +618 -0
  586. opentrons/util/__init__.py +1 -0
  587. opentrons/util/async_helpers.py +166 -0
  588. opentrons/util/broker.py +84 -0
  589. opentrons/util/change_notifier.py +47 -0
  590. opentrons/util/entrypoint_util.py +278 -0
  591. opentrons/util/get_union_elements.py +26 -0
  592. opentrons/util/helpers.py +6 -0
  593. opentrons/util/linal.py +178 -0
  594. opentrons/util/logging_config.py +265 -0
  595. opentrons/util/logging_queue_handler.py +61 -0
  596. opentrons/util/performance_helpers.py +157 -0
  597. opentrons-8.6.0.dist-info/METADATA +37 -0
  598. opentrons-8.6.0.dist-info/RECORD +601 -0
  599. opentrons-8.6.0.dist-info/WHEEL +4 -0
  600. opentrons-8.6.0.dist-info/entry_points.txt +3 -0
  601. opentrons-8.6.0.dist-info/licenses/LICENSE +202 -0
@@ -0,0 +1,1153 @@
1
+ """ProtocolEngine-based Protocol API core implementation."""
2
+
3
+ from __future__ import annotations
4
+ from typing import Dict, Optional, Type, Union, List, Tuple, TYPE_CHECKING
5
+
6
+ from opentrons_shared_data.liquid_classes import LiquidClassDefinitionDoesNotExist
7
+ from opentrons_shared_data.deck.types import DeckDefinitionV5, SlotDefV3
8
+ from opentrons_shared_data.labware.labware_definition import (
9
+ labware_definition_type_adapter,
10
+ )
11
+ from opentrons_shared_data.labware.types import LabwareDefinition as LabwareDefDict
12
+ from opentrons_shared_data import liquid_classes
13
+ from opentrons_shared_data.liquid_classes.liquid_class_definition import (
14
+ LiquidClassSchemaV1,
15
+ )
16
+ from opentrons_shared_data.pipette.types import PipetteNameType
17
+ from opentrons_shared_data.robot.types import RobotType
18
+
19
+ from opentrons.types import (
20
+ DeckSlotName,
21
+ Location,
22
+ Mount,
23
+ MountType,
24
+ Point,
25
+ StagingSlotName,
26
+ )
27
+ from opentrons.hardware_control import SyncHardwareAPI, SynchronousAdapter
28
+ from opentrons.hardware_control.modules import AbstractModule
29
+ from opentrons.hardware_control.modules.types import ModuleModel, ModuleType
30
+ from opentrons.hardware_control.types import DoorState
31
+ from opentrons.protocols.api_support.util import AxisMaxSpeeds
32
+ from opentrons.protocols.api_support.types import APIVersion
33
+
34
+ from opentrons.protocol_engine import commands as cmd
35
+ from opentrons.protocol_engine.commands import LoadModuleResult
36
+ from opentrons.protocol_engine import (
37
+ DeckSlotLocation,
38
+ AddressableAreaLocation,
39
+ ModuleLocation,
40
+ OnLabwareLocation,
41
+ ModuleModel as EngineModuleModel,
42
+ LabwareMovementStrategy,
43
+ LabwareOffsetVector,
44
+ LoadedLabware,
45
+ LoadedModule,
46
+ )
47
+ from opentrons.protocol_engine.types import (
48
+ ModuleModel as ProtocolEngineModuleModel,
49
+ OFF_DECK_LOCATION,
50
+ SYSTEM_LOCATION,
51
+ LoadableLabwareLocation,
52
+ NonStackedLocation,
53
+ )
54
+ from opentrons.protocol_engine.clients import SyncClient as ProtocolEngineClient
55
+ from opentrons.protocol_engine.errors import (
56
+ LabwareNotLoadedOnModuleError,
57
+ LabwareNotLoadedOnLabwareError,
58
+ )
59
+
60
+ from ... import validation
61
+ from ..._types import OffDeckType
62
+ from ..._liquid import Liquid, LiquidClass
63
+ from ...disposal_locations import TrashBin, WasteChute
64
+ from ..protocol import AbstractProtocol
65
+ from ..labware import LabwareLoadParams
66
+ from .labware import LabwareCore
67
+ from .instrument import InstrumentCore
68
+ from .robot import RobotCore
69
+ from .module_core import (
70
+ ModuleCore,
71
+ TemperatureModuleCore,
72
+ MagneticModuleCore,
73
+ ThermocyclerModuleCore,
74
+ HeaterShakerModuleCore,
75
+ NonConnectedModuleCore,
76
+ MagneticBlockCore,
77
+ AbsorbanceReaderCore,
78
+ FlexStackerCore,
79
+ )
80
+ from .exceptions import InvalidModuleLocationError
81
+ from . import load_labware_params, deck_conflict, overlap_versions
82
+ from opentrons.protocol_engine.resources import labware_validation
83
+
84
+ if TYPE_CHECKING:
85
+ from ...labware import Labware
86
+
87
+
88
+ class ProtocolCore(
89
+ AbstractProtocol[
90
+ InstrumentCore,
91
+ LabwareCore,
92
+ Union[ModuleCore, NonConnectedModuleCore],
93
+ ]
94
+ ):
95
+ """Protocol API core using a ProtocolEngine.
96
+
97
+ Args:
98
+ engine_client: A client to the ProtocolEngine that is executing the protocol.
99
+ api_version: The Python Protocol API versionat which this core is operating.
100
+ sync_hardware: A SynchronousAdapter-wrapped Hardware Control API.
101
+ """
102
+
103
+ def __init__(
104
+ self,
105
+ engine_client: ProtocolEngineClient,
106
+ api_version: APIVersion,
107
+ sync_hardware: SyncHardwareAPI,
108
+ ) -> None:
109
+ self._engine_client = engine_client
110
+ self._api_version = api_version
111
+ self._sync_hardware = sync_hardware
112
+ self._last_location: Optional[Union[Location, TrashBin, WasteChute]] = None
113
+ self._last_mount: Optional[Mount] = None
114
+ self._labware_cores_by_id: Dict[str, LabwareCore] = {}
115
+ self._module_cores_by_id: Dict[
116
+ str, Union[ModuleCore, NonConnectedModuleCore]
117
+ ] = {}
118
+ self._disposal_locations: List[Union[Labware, TrashBin, WasteChute]] = []
119
+ self._liquid_class_def_cache: Dict[Tuple[str, int], LiquidClassSchemaV1] = {}
120
+ self._load_fixed_trash()
121
+
122
+ @property
123
+ def api_version(self) -> APIVersion:
124
+ """Get the api version protocol target."""
125
+ return self._api_version
126
+
127
+ @property
128
+ def robot_type(self) -> RobotType:
129
+ return self._engine_client.state.config.robot_type
130
+
131
+ @property
132
+ def fixed_trash(self) -> Optional[LabwareCore]:
133
+ """Get the fixed trash labware."""
134
+ trash_id = self._engine_client.state.labware.get_fixed_trash_id()
135
+ if trash_id is not None and self._api_version < APIVersion(2, 16):
136
+ return self._labware_cores_by_id[trash_id]
137
+ return None
138
+
139
+ def _load_fixed_trash(self) -> None:
140
+ if self.robot_type == "OT-2 Standard" or self._api_version < APIVersion(2, 16):
141
+ trash_id = self._engine_client.state.labware.get_fixed_trash_id()
142
+ if trash_id is not None:
143
+ self._labware_cores_by_id[trash_id] = LabwareCore(
144
+ labware_id=trash_id,
145
+ engine_client=self._engine_client,
146
+ )
147
+
148
+ def append_disposal_location(
149
+ self,
150
+ disposal_location: Union[Labware, TrashBin, WasteChute],
151
+ ) -> None:
152
+ """Append a disposal location object to the core."""
153
+ self._disposal_locations.append(disposal_location)
154
+
155
+ def _add_disposal_location_to_engine(
156
+ self, disposal_location: Union[TrashBin, WasteChute]
157
+ ) -> None:
158
+ """Verify and add disposal location to engine store and append it to the core."""
159
+ self._engine_client.state.addressable_areas.raise_if_area_not_in_deck_configuration(
160
+ disposal_location.area_name
161
+ )
162
+ if isinstance(disposal_location, TrashBin):
163
+ deck_conflict.check(
164
+ engine_state=self._engine_client.state,
165
+ new_trash_bin=disposal_location,
166
+ existing_disposal_locations=self._disposal_locations,
167
+ # TODO: We can now fetch these IDs from engine too.
168
+ # See comment in self.load_labware().
169
+ #
170
+ # Wrapping .keys() in list() is just to make Decoy verification easier.
171
+ existing_labware_ids=list(self._labware_cores_by_id.keys()),
172
+ existing_module_ids=list(self._module_cores_by_id.keys()),
173
+ )
174
+ self._engine_client.add_addressable_area(disposal_location.area_name)
175
+ self.append_disposal_location(disposal_location)
176
+
177
+ def get_disposal_locations(self) -> List[Union[Labware, TrashBin, WasteChute]]:
178
+ """Get disposal locations."""
179
+ return self._disposal_locations
180
+
181
+ def get_max_speeds(self) -> AxisMaxSpeeds:
182
+ """Get a control interface for maximum move speeds."""
183
+ raise NotImplementedError("ProtocolCore.get_max_speeds not implemented")
184
+
185
+ def get_hardware(self) -> SyncHardwareAPI:
186
+ """Get direct access to a hardware control interface."""
187
+ return self._sync_hardware
188
+
189
+ def is_simulating(self) -> bool:
190
+ """Get whether the protocol is being analyzed or actually run."""
191
+ return self._engine_client.state.config.ignore_pause
192
+
193
+ def add_labware_definition(
194
+ self,
195
+ definition: LabwareDefDict,
196
+ ) -> LabwareLoadParams:
197
+ """Add a labware definition to the set of loadable definitions."""
198
+ uri = self._engine_client.add_labware_definition(
199
+ labware_definition_type_adapter.validate_python(definition)
200
+ )
201
+ return LabwareLoadParams.from_uri(uri)
202
+
203
+ def load_labware(
204
+ self,
205
+ load_name: str,
206
+ location: Union[
207
+ DeckSlotName,
208
+ StagingSlotName,
209
+ LabwareCore,
210
+ ModuleCore,
211
+ NonConnectedModuleCore,
212
+ OffDeckType,
213
+ ],
214
+ label: Optional[str],
215
+ namespace: Optional[str],
216
+ version: Optional[int],
217
+ ) -> LabwareCore:
218
+ """Load a labware using its identifying parameters."""
219
+ load_location = self._convert_labware_location(location=location)
220
+
221
+ custom_labware_params = (
222
+ self._engine_client.state.labware.find_custom_labware_load_params()
223
+ )
224
+ namespace, version = load_labware_params.resolve(
225
+ load_name, namespace, version, custom_labware_params, self._api_version
226
+ )
227
+
228
+ load_result = self._engine_client.execute_command_without_recovery(
229
+ cmd.LoadLabwareParams(
230
+ loadName=load_name,
231
+ location=load_location,
232
+ namespace=namespace,
233
+ version=version,
234
+ displayName=label,
235
+ )
236
+ )
237
+ # FIXME(jbl, 2023-08-14) validating after loading the object issue
238
+ validation.ensure_definition_is_labware(load_result.definition)
239
+ validation.ensure_definition_is_not_lid_after_api_version(
240
+ self.api_version, load_result.definition
241
+ )
242
+
243
+ # FIXME(mm, 2023-02-21):
244
+ #
245
+ # We're wrongly checking for deck conflicts *after* we've already loaded the
246
+ # labware into the ProtocolEngine. If it turns out there is a conflict,
247
+ # and this check raises, it will leave this object and its ProtocolEngine
248
+ # in a confusing inconsistent state.
249
+ #
250
+ # I expect we can get away with this in practice a lot of the time because
251
+ # exceptions in Python protocols are mostly treated as fatal, anyway.
252
+ # Users rarely catch them.
253
+ deck_conflict.check(
254
+ engine_state=self._engine_client.state,
255
+ new_labware_id=load_result.labwareId,
256
+ existing_disposal_locations=self._disposal_locations,
257
+ # TODO (spp, 2023-11-27): We've been using IDs from _labware_cores_by_id
258
+ # and _module_cores_by_id instead of getting the lists directly from engine
259
+ # because of the chance of engine carrying labware IDs from LPC too.
260
+ # But with https://github.com/Opentrons/opentrons/pull/13943,
261
+ # & LPC in maintenance runs, we can now rely on engine state for these IDs too.
262
+ # Wrapping .keys() in list() is just to make Decoy verification easier.
263
+ existing_labware_ids=list(self._labware_cores_by_id.keys()),
264
+ existing_module_ids=list(self._module_cores_by_id.keys()),
265
+ )
266
+
267
+ labware_core = LabwareCore(
268
+ labware_id=load_result.labwareId,
269
+ engine_client=self._engine_client,
270
+ )
271
+
272
+ self._labware_cores_by_id[labware_core.labware_id] = labware_core
273
+
274
+ return labware_core
275
+
276
+ def load_adapter(
277
+ self,
278
+ load_name: str,
279
+ location: Union[
280
+ DeckSlotName,
281
+ StagingSlotName,
282
+ ModuleCore,
283
+ NonConnectedModuleCore,
284
+ OffDeckType,
285
+ ],
286
+ namespace: Optional[str],
287
+ version: Optional[int],
288
+ ) -> LabwareCore:
289
+ """Load an adapter using its identifying parameters"""
290
+ load_location = self._get_non_stacked_location(location=location)
291
+
292
+ custom_labware_params = (
293
+ self._engine_client.state.labware.find_custom_labware_load_params()
294
+ )
295
+ namespace, version = load_labware_params.resolve(
296
+ load_name, namespace, version, custom_labware_params, self._api_version
297
+ )
298
+ load_result = self._engine_client.execute_command_without_recovery(
299
+ cmd.LoadLabwareParams(
300
+ loadName=load_name,
301
+ location=load_location,
302
+ namespace=namespace,
303
+ version=version,
304
+ )
305
+ )
306
+ # FIXME(jbl, 2023-08-14) validating after loading the object issue
307
+ validation.ensure_definition_is_adapter(load_result.definition)
308
+
309
+ # FIXME(jbl, 2023-06-23) read fixme above:
310
+ deck_conflict.check(
311
+ engine_state=self._engine_client.state,
312
+ new_labware_id=load_result.labwareId,
313
+ existing_disposal_locations=self._disposal_locations,
314
+ # TODO: We can now fetch these IDs from engine too.
315
+ # See comment in self.load_labware().
316
+ #
317
+ # Wrapping .keys() in list() is just to make Decoy verification easier.
318
+ existing_labware_ids=list(self._labware_cores_by_id.keys()),
319
+ existing_module_ids=list(self._module_cores_by_id.keys()),
320
+ )
321
+
322
+ labware_core = LabwareCore(
323
+ labware_id=load_result.labwareId,
324
+ engine_client=self._engine_client,
325
+ )
326
+
327
+ self._labware_cores_by_id[labware_core.labware_id] = labware_core
328
+
329
+ return labware_core
330
+
331
+ def load_lid(
332
+ self,
333
+ load_name: str,
334
+ location: LabwareCore,
335
+ namespace: Optional[str],
336
+ version: Optional[int],
337
+ ) -> LabwareCore:
338
+ """Load an individual lid using its identifying parameters. Must be loaded on an existing Labware."""
339
+ load_location = self._convert_labware_location(location=location)
340
+ custom_labware_params = (
341
+ self._engine_client.state.labware.find_custom_labware_load_params()
342
+ )
343
+ namespace, version = load_labware_params.resolve(
344
+ load_name, namespace, version, custom_labware_params, self._api_version
345
+ )
346
+ load_result = self._engine_client.execute_command_without_recovery(
347
+ cmd.LoadLidParams(
348
+ loadName=load_name,
349
+ location=load_location,
350
+ namespace=namespace,
351
+ version=version,
352
+ )
353
+ )
354
+ # FIXME(chb, 2024-12-06) validating after loading the object issue
355
+ validation.ensure_definition_is_lid(load_result.definition)
356
+
357
+ deck_conflict.check(
358
+ engine_state=self._engine_client.state,
359
+ new_labware_id=load_result.labwareId,
360
+ existing_disposal_locations=self._disposal_locations,
361
+ # TODO: We can now fetch these IDs from engine too.
362
+ # See comment in self.load_labware().
363
+ #
364
+ # Wrapping .keys() in list() is just to make Decoy verification easier.
365
+ existing_labware_ids=list(self._labware_cores_by_id.keys()),
366
+ existing_module_ids=list(self._module_cores_by_id.keys()),
367
+ )
368
+
369
+ labware_core = LabwareCore(
370
+ labware_id=load_result.labwareId,
371
+ engine_client=self._engine_client,
372
+ )
373
+
374
+ self._labware_cores_by_id[labware_core.labware_id] = labware_core
375
+ return labware_core
376
+
377
+ def move_labware(
378
+ self,
379
+ labware_core: LabwareCore,
380
+ new_location: Union[
381
+ DeckSlotName,
382
+ StagingSlotName,
383
+ LabwareCore,
384
+ ModuleCore,
385
+ NonConnectedModuleCore,
386
+ OffDeckType,
387
+ WasteChute,
388
+ TrashBin,
389
+ ],
390
+ use_gripper: bool,
391
+ pause_for_manual_move: bool,
392
+ pick_up_offset: Optional[Tuple[float, float, float]],
393
+ drop_offset: Optional[Tuple[float, float, float]],
394
+ ) -> None:
395
+ """Move the given labware to a new location."""
396
+ if use_gripper:
397
+ strategy = LabwareMovementStrategy.USING_GRIPPER
398
+ elif pause_for_manual_move:
399
+ strategy = LabwareMovementStrategy.MANUAL_MOVE_WITH_PAUSE
400
+ else:
401
+ strategy = LabwareMovementStrategy.MANUAL_MOVE_WITHOUT_PAUSE
402
+
403
+ _pick_up_offset = (
404
+ LabwareOffsetVector(
405
+ x=pick_up_offset[0], y=pick_up_offset[1], z=pick_up_offset[2]
406
+ )
407
+ if pick_up_offset
408
+ else None
409
+ )
410
+ _drop_offset = (
411
+ LabwareOffsetVector(x=drop_offset[0], y=drop_offset[1], z=drop_offset[2])
412
+ if drop_offset
413
+ else None
414
+ )
415
+
416
+ to_location = self._convert_labware_location(location=new_location)
417
+
418
+ self._engine_client.execute_command(
419
+ cmd.MoveLabwareParams(
420
+ labwareId=labware_core.labware_id,
421
+ newLocation=to_location,
422
+ strategy=strategy,
423
+ pickUpOffset=_pick_up_offset,
424
+ dropOffset=_drop_offset,
425
+ )
426
+ )
427
+
428
+ if strategy == LabwareMovementStrategy.USING_GRIPPER:
429
+ # Clear out last location since it is not relevant to pipetting
430
+ # and we only use last location for in-place pipetting commands
431
+ self.set_last_location(location=None, mount=Mount.EXTENSION)
432
+
433
+ # FIXME(jbl, 2024-01-04) deck conflict after execution logic issue, read notes in load_labware for more info:
434
+ deck_conflict.check(
435
+ engine_state=self._engine_client.state,
436
+ new_labware_id=labware_core.labware_id,
437
+ existing_disposal_locations=self._disposal_locations,
438
+ # TODO: We can now fetch these IDs from engine too.
439
+ # See comment in self.load_labware().
440
+ existing_labware_ids=[
441
+ labware_id
442
+ for labware_id in self._labware_cores_by_id
443
+ if labware_id != labware_core.labware_id
444
+ ],
445
+ existing_module_ids=list(self._module_cores_by_id.keys()),
446
+ )
447
+
448
+ def move_lid( # noqa: C901
449
+ self,
450
+ source_location: Union[DeckSlotName, StagingSlotName, LabwareCore],
451
+ new_location: Union[
452
+ DeckSlotName,
453
+ StagingSlotName,
454
+ LabwareCore,
455
+ OffDeckType,
456
+ WasteChute,
457
+ TrashBin,
458
+ ],
459
+ use_gripper: bool,
460
+ pause_for_manual_move: bool,
461
+ pick_up_offset: Optional[Tuple[float, float, float]],
462
+ drop_offset: Optional[Tuple[float, float, float]],
463
+ ) -> LabwareCore | None:
464
+ """Move the given lid to a new location."""
465
+ if use_gripper:
466
+ strategy = LabwareMovementStrategy.USING_GRIPPER
467
+ elif pause_for_manual_move:
468
+ strategy = LabwareMovementStrategy.MANUAL_MOVE_WITH_PAUSE
469
+ else:
470
+ strategy = LabwareMovementStrategy.MANUAL_MOVE_WITHOUT_PAUSE
471
+
472
+ if isinstance(source_location, DeckSlotName) or isinstance(
473
+ source_location, StagingSlotName
474
+ ):
475
+ # Find the source labware at the provided deck slot
476
+ labware_in_slot = self._engine_client.state.labware.get_by_slot(
477
+ source_location
478
+ )
479
+ if labware_in_slot is None:
480
+ raise LabwareNotLoadedOnLabwareError(
481
+ "Lid cannot be loaded on non-labware position."
482
+ )
483
+ else:
484
+ labware = LabwareCore(labware_in_slot.id, self._engine_client)
485
+ else:
486
+ labware = source_location
487
+
488
+ # if this is a labware stack, we need to find the labware at the top of the stack
489
+ if labware_validation.is_lid_stack(labware.load_name):
490
+ lid_id = self._engine_client.state.labware.get_highest_child_labware(
491
+ labware.labware_id
492
+ )
493
+ # if this is a labware with a lid, we just need to find its lid_id
494
+ else:
495
+ lid = self._engine_client.state.labware.get_lid_by_labware_id(
496
+ labware.labware_id
497
+ )
498
+ if lid is not None:
499
+ lid_id = lid.id
500
+ else:
501
+ raise ValueError("Cannot move a lid off of a labware with no lid.")
502
+
503
+ _pick_up_offset = (
504
+ LabwareOffsetVector(
505
+ x=pick_up_offset[0], y=pick_up_offset[1], z=pick_up_offset[2]
506
+ )
507
+ if pick_up_offset
508
+ else None
509
+ )
510
+ _drop_offset = (
511
+ LabwareOffsetVector(x=drop_offset[0], y=drop_offset[1], z=drop_offset[2])
512
+ if drop_offset
513
+ else None
514
+ )
515
+
516
+ create_new_lid_stack = False
517
+
518
+ if isinstance(new_location, DeckSlotName) or isinstance(
519
+ new_location, StagingSlotName
520
+ ):
521
+ # Find the destination labware at the provided deck slot
522
+ destination_labware_in_slot = self._engine_client.state.labware.get_by_slot(
523
+ new_location
524
+ )
525
+ if destination_labware_in_slot is None:
526
+ to_location = self._convert_labware_location(location=new_location)
527
+ # absolutely must make a new lid stack
528
+ create_new_lid_stack = True
529
+ else:
530
+ highest_child_location = (
531
+ self._engine_client.state.labware.get_highest_child_labware(
532
+ destination_labware_in_slot.id
533
+ )
534
+ )
535
+ if labware_validation.validate_definition_is_adapter(
536
+ self._engine_client.state.labware.get_definition(
537
+ highest_child_location
538
+ )
539
+ ):
540
+ # absolutely must make a new lid stack
541
+ create_new_lid_stack = True
542
+
543
+ to_location = self._convert_labware_location(
544
+ location=LabwareCore(highest_child_location, self._engine_client)
545
+ )
546
+ elif isinstance(new_location, LabwareCore):
547
+ highest_child_location = (
548
+ self._engine_client.state.labware.get_highest_child_labware(
549
+ new_location.labware_id
550
+ )
551
+ )
552
+ if labware_validation.validate_definition_is_adapter(
553
+ self._engine_client.state.labware.get_definition(highest_child_location)
554
+ ):
555
+ # absolutely must make a new lid stack
556
+ create_new_lid_stack = True
557
+ to_location = self._convert_labware_location(
558
+ location=LabwareCore(highest_child_location, self._engine_client)
559
+ )
560
+ else:
561
+ to_location = self._convert_labware_location(location=new_location)
562
+
563
+ output_result = None
564
+ if create_new_lid_stack:
565
+ # Make a new lid stack object that is empty
566
+ result = self._engine_client.execute_command_without_recovery(
567
+ cmd.LoadLidStackParams(
568
+ location=SYSTEM_LOCATION,
569
+ loadName="empty",
570
+ version=1,
571
+ namespace="empty",
572
+ quantity=0,
573
+ )
574
+ )
575
+
576
+ # Move the lid stack object from the SYSTEM_LOCATION space to the desired deck location
577
+ self._engine_client.execute_command(
578
+ cmd.MoveLabwareParams(
579
+ labwareId=result.stackLabwareId,
580
+ newLocation=to_location,
581
+ strategy=LabwareMovementStrategy.MANUAL_MOVE_WITHOUT_PAUSE,
582
+ pickUpOffset=None,
583
+ dropOffset=None,
584
+ )
585
+ )
586
+
587
+ output_result = LabwareCore(
588
+ labware_id=result.stackLabwareId, engine_client=self._engine_client
589
+ )
590
+ destination = self._convert_labware_location(location=output_result)
591
+ else:
592
+ destination = to_location
593
+
594
+ self._engine_client.execute_command(
595
+ cmd.MoveLabwareParams(
596
+ labwareId=lid_id,
597
+ newLocation=destination,
598
+ strategy=strategy,
599
+ pickUpOffset=_pick_up_offset,
600
+ dropOffset=_drop_offset,
601
+ )
602
+ )
603
+
604
+ # Handle leftover empty lid stack if there is one
605
+ if (
606
+ labware_validation.is_lid_stack(labware.load_name)
607
+ and self._engine_client.state.labware.get_highest_child_labware(
608
+ labware_id=labware.labware_id
609
+ )
610
+ == labware.labware_id
611
+ ):
612
+ # The originating lid stack is now empty, so we need to move it to the SYSTEM_LOCATION
613
+ self._engine_client.execute_command(
614
+ cmd.MoveLabwareParams(
615
+ labwareId=labware.labware_id,
616
+ newLocation=SYSTEM_LOCATION,
617
+ strategy=LabwareMovementStrategy.MANUAL_MOVE_WITHOUT_PAUSE,
618
+ pickUpOffset=None,
619
+ dropOffset=None,
620
+ )
621
+ )
622
+
623
+ if strategy == LabwareMovementStrategy.USING_GRIPPER:
624
+ # Clear out last location since it is not relevant to pipetting
625
+ # and we only use last location for in-place pipetting commands
626
+ self.set_last_location(location=None, mount=Mount.EXTENSION)
627
+
628
+ # FIXME(jbl, 2024-01-04) deck conflict after execution logic issue, read notes in load_labware for more info:
629
+ deck_conflict.check(
630
+ engine_state=self._engine_client.state,
631
+ new_labware_id=lid_id,
632
+ existing_disposal_locations=self._disposal_locations,
633
+ # TODO: We can now fetch these IDs from engine too.
634
+ # See comment in self.load_labware().
635
+ existing_labware_ids=[
636
+ labware_id
637
+ for labware_id in self._labware_cores_by_id
638
+ if labware_id != labware_id
639
+ ],
640
+ existing_module_ids=list(self._module_cores_by_id.keys()),
641
+ )
642
+
643
+ return output_result
644
+
645
+ def _resolve_module_hardware(
646
+ self, serial_number: str, model: ModuleModel
647
+ ) -> AbstractModule:
648
+ """Resolve a module serial number to module hardware API."""
649
+ if self.is_simulating():
650
+ return self._sync_hardware.create_simulating_module(model) # type: ignore[no-any-return]
651
+
652
+ for module_hardware in self._sync_hardware.attached_modules:
653
+ if serial_number == module_hardware.device_info["serial"]:
654
+ return module_hardware # type: ignore[no-any-return]
655
+
656
+ raise RuntimeError(f"Could not find specified module: {model.value}")
657
+
658
+ def load_module(
659
+ self,
660
+ model: ModuleModel,
661
+ deck_slot: Optional[DeckSlotName],
662
+ configuration: Optional[str],
663
+ ) -> Union[ModuleCore, NonConnectedModuleCore]:
664
+ """Load a module into the protocol."""
665
+ assert configuration is None, "Module `configuration` is deprecated"
666
+
667
+ module_type = ModuleType.from_model(model)
668
+ # TODO(mc, 2022-10-20): move to public ProtocolContext
669
+ # once `Deck` and `ProtocolEngine` play nicely together
670
+ if deck_slot is None:
671
+ module_type = ModuleType.from_model(model)
672
+ if module_type == ModuleType.THERMOCYCLER:
673
+ deck_slot = DeckSlotName.SLOT_7
674
+ else:
675
+ raise InvalidModuleLocationError(deck_slot, model.name)
676
+
677
+ robot_type = self._engine_client.state.config.robot_type
678
+ # todo(mm, 2024-12-03): This might be possible to remove:
679
+ # Protocol Engine will normalize the deck slot itself.
680
+ normalized_deck_slot = deck_slot.to_equivalent_for_robot_type(robot_type)
681
+
682
+ result = self._engine_client.execute_command_without_recovery(
683
+ cmd.LoadModuleParams(
684
+ model=EngineModuleModel(model),
685
+ location=DeckSlotLocation(slotName=normalized_deck_slot),
686
+ )
687
+ )
688
+
689
+ module_core = self._get_module_core(load_module_result=result, model=model)
690
+
691
+ # FIXME(mm, 2023-02-21):
692
+ # We're wrongly doing this conflict check *after* we've already loaded the
693
+ # module into the ProtocolEngine. See FIXME comment in self.load_labware().
694
+ deck_conflict.check(
695
+ engine_state=self._engine_client.state,
696
+ new_module_id=result.moduleId,
697
+ existing_disposal_locations=self._disposal_locations,
698
+ # TODO: We can now fetch these IDs from engine too.
699
+ # See comment in self.load_labware().
700
+ #
701
+ # Wrapping .keys() in list() is just to make Decoy verification easier.
702
+ existing_labware_ids=list(self._labware_cores_by_id.keys()),
703
+ existing_module_ids=list(self._module_cores_by_id.keys()),
704
+ )
705
+
706
+ self._module_cores_by_id[module_core.module_id] = module_core
707
+
708
+ return module_core
709
+
710
+ def _create_non_connected_module_core(
711
+ self, load_module_result: LoadModuleResult
712
+ ) -> NonConnectedModuleCore:
713
+ return MagneticBlockCore(
714
+ module_id=load_module_result.moduleId,
715
+ engine_client=self._engine_client,
716
+ api_version=self.api_version,
717
+ protocol_core=self,
718
+ )
719
+
720
+ def _create_module_core(
721
+ self, load_module_result: LoadModuleResult, model: ModuleModel
722
+ ) -> ModuleCore:
723
+ module_core_cls: Type[ModuleCore] = ModuleCore
724
+
725
+ type_lookup: Dict[ModuleType, Type[ModuleCore]] = {
726
+ ModuleType.TEMPERATURE: TemperatureModuleCore,
727
+ ModuleType.MAGNETIC: MagneticModuleCore,
728
+ ModuleType.THERMOCYCLER: ThermocyclerModuleCore,
729
+ ModuleType.HEATER_SHAKER: HeaterShakerModuleCore,
730
+ ModuleType.ABSORBANCE_READER: AbsorbanceReaderCore,
731
+ ModuleType.FLEX_STACKER: FlexStackerCore,
732
+ }
733
+
734
+ module_type = load_module_result.model.as_type()
735
+
736
+ module_core_cls = type_lookup[module_type]
737
+
738
+ assert (
739
+ load_module_result.serialNumber is not None
740
+ ), "Expected a connected module but did not get a serial number."
741
+ selected_hardware = self._resolve_module_hardware(
742
+ load_module_result.serialNumber, model
743
+ )
744
+
745
+ return module_core_cls(
746
+ module_id=load_module_result.moduleId,
747
+ engine_client=self._engine_client,
748
+ api_version=self.api_version,
749
+ sync_module_hardware=SynchronousAdapter(selected_hardware),
750
+ protocol_core=self,
751
+ )
752
+
753
+ def _get_module_core(
754
+ self, load_module_result: LoadModuleResult, model: ModuleModel
755
+ ) -> Union[ModuleCore, NonConnectedModuleCore]:
756
+ if ProtocolEngineModuleModel.is_magnetic_block(load_module_result.model):
757
+ return self._create_non_connected_module_core(load_module_result)
758
+ else:
759
+ return self._create_module_core(
760
+ load_module_result=load_module_result, model=model
761
+ )
762
+
763
+ def add_or_get_labware_core(self, labware_id: str) -> LabwareCore:
764
+ """Create a LabwareCore and add it to the map or return one if it exists."""
765
+ if labware_id in self._labware_cores_by_id:
766
+ return self._labware_cores_by_id[labware_id]
767
+ else:
768
+ core = LabwareCore(labware_id, self._engine_client)
769
+ self._labware_cores_by_id[labware_id] = core
770
+ return core
771
+
772
+ def load_robot(self) -> RobotCore:
773
+ """Load a robot core into the RobotContext."""
774
+ return RobotCore(
775
+ engine_client=self._engine_client, sync_hardware_api=self._sync_hardware
776
+ )
777
+
778
+ def load_instrument(
779
+ self,
780
+ instrument_name: PipetteNameType,
781
+ mount: Mount,
782
+ liquid_presence_detection: bool = False,
783
+ ) -> InstrumentCore:
784
+ """Load an instrument into the protocol.
785
+
786
+ Args:
787
+ instrument_name: Load name of the instrument.
788
+ mount: Mount the instrument is attached to.
789
+
790
+ Returns:
791
+ An instrument core configured to use the requested instrument.
792
+ """
793
+ engine_mount = MountType[mount.name]
794
+ load_result = self._engine_client.execute_command_without_recovery(
795
+ cmd.LoadPipetteParams(
796
+ pipetteName=instrument_name,
797
+ mount=engine_mount,
798
+ tipOverlapNotAfterVersion=overlap_versions.overlap_for_api_version(
799
+ self._api_version
800
+ ),
801
+ liquidPresenceDetection=liquid_presence_detection,
802
+ )
803
+ )
804
+
805
+ return InstrumentCore(
806
+ pipette_id=load_result.pipetteId,
807
+ engine_client=self._engine_client,
808
+ sync_hardware_api=self._sync_hardware,
809
+ protocol_core=self,
810
+ # TODO(mm, 2022-11-10): Deduplicate "400" with legacy core.
811
+ default_movement_speed=400,
812
+ )
813
+
814
+ def load_trash_bin(self, slot_name: DeckSlotName, area_name: str) -> TrashBin:
815
+ """Load a deck configuration based trash bin.
816
+
817
+ Args:
818
+ slot_name: the slot the trash is being loaded into.
819
+ area_name: the addressable area name of the trash.
820
+
821
+ Returns:
822
+ A trash bin object.
823
+ """
824
+ trash_bin = TrashBin(
825
+ location=slot_name,
826
+ addressable_area_name=area_name,
827
+ api_version=self._api_version,
828
+ engine_client=self._engine_client,
829
+ )
830
+ self._add_disposal_location_to_engine(trash_bin)
831
+ return trash_bin
832
+
833
+ def load_ot2_fixed_trash_bin(self) -> None:
834
+ """Load a deck configured OT-2 fixed trash in Slot 12."""
835
+ _fixed_trash_trash_bin = TrashBin(
836
+ location=DeckSlotName.FIXED_TRASH,
837
+ addressable_area_name="fixedTrash",
838
+ api_version=self._api_version,
839
+ engine_client=self._engine_client,
840
+ )
841
+ # We are just appending the fixed trash to the core's internal list here, not adding it to the engine via
842
+ # the core, since that method works through the SyncClient and if called from here, will cause protocols
843
+ # to deadlock. Instead, that method is called in protocol engine directly in create_protocol_context after
844
+ # ProtocolContext is initialized.
845
+ self.append_disposal_location(_fixed_trash_trash_bin)
846
+
847
+ def load_waste_chute(self) -> WasteChute:
848
+ """Load a deck configured waste chute into Slot D3.
849
+
850
+ Returns:
851
+ A waste chute object.
852
+ """
853
+ waste_chute = WasteChute(
854
+ engine_client=self._engine_client, api_version=self._api_version
855
+ )
856
+ self._add_disposal_location_to_engine(waste_chute)
857
+ return waste_chute
858
+
859
+ def pause(self, msg: Optional[str]) -> None:
860
+ """Pause the protocol."""
861
+ self._engine_client.execute_command(cmd.WaitForResumeParams(message=msg))
862
+
863
+ def comment(self, msg: str) -> None:
864
+ """Create a comment in the protocol to be shown in the log."""
865
+ self._engine_client.execute_command(cmd.CommentParams(message=msg))
866
+
867
+ def delay(self, seconds: float, msg: Optional[str]) -> None:
868
+ """Wait for a period of time before proceeding."""
869
+ self._engine_client.execute_command(
870
+ cmd.WaitForDurationParams(seconds=seconds, message=msg)
871
+ )
872
+
873
+ def home(self) -> None:
874
+ """Move all axes to their home positions."""
875
+ self._engine_client.execute_command(cmd.HomeParams(axes=None))
876
+
877
+ def set_rail_lights(self, on: bool) -> None:
878
+ """Set the device's rail lights."""
879
+ self._engine_client.execute_command(cmd.SetRailLightsParams(on=on))
880
+
881
+ def get_rail_lights_on(self) -> bool:
882
+ """Get whether the device's rail lights are on."""
883
+ return self._sync_hardware.get_lights()["rails"] # type: ignore[no-any-return]
884
+
885
+ def door_closed(self) -> bool:
886
+ """Get whether the device's front door is closed."""
887
+ return self._sync_hardware.door_state == DoorState.CLOSED # type: ignore[no-any-return]
888
+
889
+ def get_last_location(
890
+ self,
891
+ mount: Optional[Mount] = None,
892
+ ) -> Optional[Union[Location, TrashBin, WasteChute]]:
893
+ """Get the last accessed location."""
894
+ if mount is None or mount == self._last_mount:
895
+ return self._last_location
896
+
897
+ return None
898
+
899
+ def set_last_location(
900
+ self,
901
+ location: Optional[Union[Location, TrashBin, WasteChute]],
902
+ mount: Optional[Mount] = None,
903
+ ) -> None:
904
+ """Set the last accessed location."""
905
+ self._last_location = location
906
+ self._last_mount = mount
907
+
908
+ def load_lid_stack(
909
+ self,
910
+ load_name: str,
911
+ location: Union[DeckSlotName, StagingSlotName, LabwareCore],
912
+ quantity: int,
913
+ namespace: Optional[str],
914
+ version: Optional[int],
915
+ ) -> LabwareCore:
916
+ """Load a Stack of Lids to a given location, creating a Lid Stack."""
917
+ if quantity < 1:
918
+ raise ValueError(
919
+ "When loading a lid stack quantity cannot be less than one."
920
+ )
921
+ if isinstance(location, DeckSlotName) or isinstance(location, StagingSlotName):
922
+ load_location = self._convert_labware_location(location=location)
923
+ else:
924
+ if isinstance(location, LabwareCore):
925
+ load_location = self._convert_labware_location(location=location)
926
+ else:
927
+ raise ValueError(
928
+ "Expected type of Labware Location for lid stack must be Labware, not Legacy Labware or Well."
929
+ )
930
+
931
+ custom_labware_params = (
932
+ self._engine_client.state.labware.find_custom_labware_load_params()
933
+ )
934
+ namespace, version = load_labware_params.resolve(
935
+ load_name, namespace, version, custom_labware_params, self._api_version
936
+ )
937
+
938
+ load_result = self._engine_client.execute_command_without_recovery(
939
+ cmd.LoadLidStackParams(
940
+ loadName=load_name,
941
+ location=load_location,
942
+ namespace=namespace,
943
+ version=version,
944
+ quantity=quantity,
945
+ )
946
+ )
947
+
948
+ # FIXME(CHB, 2024-12-04) just like load labware and load adapter we have a validating after loading the object issue
949
+ assert load_result.definition is not None
950
+ validation.ensure_definition_is_lid(load_result.definition)
951
+
952
+ deck_conflict.check(
953
+ engine_state=self._engine_client.state,
954
+ new_labware_id=load_result.stackLabwareId,
955
+ existing_disposal_locations=self._disposal_locations,
956
+ # TODO (spp, 2023-11-27): We've been using IDs from _labware_cores_by_id
957
+ # and _module_cores_by_id instead of getting the lists directly from engine
958
+ # because of the chance of engine carrying labware IDs from LPC too.
959
+ # But with https://github.com/Opentrons/opentrons/pull/13943,
960
+ # & LPC in maintenance runs, we can now rely on engine state for these IDs too.
961
+ # Wrapping .keys() in list() is just to make Decoy verification easier.
962
+ existing_labware_ids=list(self._labware_cores_by_id.keys()),
963
+ existing_module_ids=list(self._module_cores_by_id.keys()),
964
+ )
965
+
966
+ labware_core = LabwareCore(
967
+ labware_id=load_result.stackLabwareId,
968
+ engine_client=self._engine_client,
969
+ )
970
+
971
+ self._labware_cores_by_id[labware_core.labware_id] = labware_core
972
+
973
+ return labware_core
974
+
975
+ def get_deck_definition(self) -> DeckDefinitionV5:
976
+ """Get the geometry definition of the robot's deck."""
977
+ return self._engine_client.state.labware.get_deck_definition()
978
+
979
+ def get_slot_definition(
980
+ self, slot: Union[DeckSlotName, StagingSlotName]
981
+ ) -> SlotDefV3:
982
+ """Get the slot definition from the robot's deck."""
983
+ return self._engine_client.state.addressable_areas.get_slot_definition(slot.id)
984
+
985
+ def get_slot_definitions(self) -> Dict[str, SlotDefV3]:
986
+ """Get all standard slot definitions available in the deck definition."""
987
+ return self._engine_client.state.addressable_areas.get_deck_slot_definitions()
988
+
989
+ def get_staging_slot_definitions(self) -> Dict[str, SlotDefV3]:
990
+ """Get all staging slot definitions available in the deck definition."""
991
+ return (
992
+ self._engine_client.state.addressable_areas.get_staging_slot_definitions()
993
+ )
994
+
995
+ def get_slot_item(
996
+ self, slot_name: Union[DeckSlotName, StagingSlotName]
997
+ ) -> Union[LabwareCore, ModuleCore, NonConnectedModuleCore, None]:
998
+ """Get the contents of a given slot, if any."""
999
+ loaded_item = self._engine_client.state.geometry.get_slot_item(
1000
+ slot_name=slot_name
1001
+ )
1002
+
1003
+ if isinstance(loaded_item, LoadedLabware):
1004
+ return self._labware_cores_by_id[loaded_item.id]
1005
+
1006
+ if isinstance(loaded_item, LoadedModule):
1007
+ return self._module_cores_by_id[loaded_item.id]
1008
+
1009
+ return None
1010
+
1011
+ def get_labware_on_module(
1012
+ self, module_core: Union[ModuleCore, NonConnectedModuleCore]
1013
+ ) -> Optional[LabwareCore]:
1014
+ """Get the item on top of a given module, if any."""
1015
+ try:
1016
+ labware_id = self._engine_client.state.labware.get_id_by_module(
1017
+ module_core.module_id
1018
+ )
1019
+ except LabwareNotLoadedOnModuleError:
1020
+ return None
1021
+ return self.add_or_get_labware_core(labware_id)
1022
+
1023
+ def get_labware_on_labware(
1024
+ self, labware_core: LabwareCore
1025
+ ) -> Optional[LabwareCore]:
1026
+ """Get the item on top of a given labware, if any."""
1027
+ try:
1028
+ labware_id = self._engine_client.state.labware.get_id_by_labware(
1029
+ labware_core.labware_id
1030
+ )
1031
+ except LabwareNotLoadedOnLabwareError:
1032
+ return None
1033
+ return self.add_or_get_labware_core(labware_id)
1034
+
1035
+ def get_slot_center(self, slot_name: Union[DeckSlotName, StagingSlotName]) -> Point:
1036
+ """Get the absolute coordinate of a slot's center."""
1037
+ return self._engine_client.state.addressable_areas.get_addressable_area_center(
1038
+ slot_name.id
1039
+ )
1040
+
1041
+ def get_highest_z(self) -> float:
1042
+ """Get the highest Z point of all deck items."""
1043
+ return self._engine_client.state.geometry.get_all_obstacle_highest_z()
1044
+
1045
+ def get_labware_cores(self) -> List[LabwareCore]:
1046
+ """Get all loaded labware cores."""
1047
+ return list(self._labware_cores_by_id.values())
1048
+
1049
+ def get_module_cores(self) -> List[Union[ModuleCore, NonConnectedModuleCore]]:
1050
+ """Get all loaded module cores."""
1051
+ return list(self._module_cores_by_id.values())
1052
+
1053
+ def define_liquid(
1054
+ self,
1055
+ name: str,
1056
+ description: Optional[str],
1057
+ display_color: Optional[str],
1058
+ ) -> Liquid:
1059
+ """Define a liquid to load into a well."""
1060
+ liquid = self._engine_client.add_liquid(
1061
+ name=name, description=description, color=display_color
1062
+ )
1063
+
1064
+ return Liquid(
1065
+ _id=liquid.id,
1066
+ name=liquid.displayName,
1067
+ description=liquid.description,
1068
+ display_color=(liquid.displayColor.root if liquid.displayColor else None),
1069
+ )
1070
+
1071
+ def get_liquid_class(self, name: str, version: int) -> LiquidClass:
1072
+ """Get an instance of a built-in liquid class."""
1073
+ try:
1074
+ # Check if we have already loaded this liquid class' definition
1075
+ liquid_class_def = self._liquid_class_def_cache[(name, version)]
1076
+ except KeyError:
1077
+ try:
1078
+ # Fetching the liquid class data from file and parsing it
1079
+ # is an expensive operation and should be avoided.
1080
+ # Calling this often will degrade protocol execution performance.
1081
+ liquid_class_def = liquid_classes.load_definition(name, version=version)
1082
+ self._liquid_class_def_cache[(name, version)] = liquid_class_def
1083
+ except LiquidClassDefinitionDoesNotExist:
1084
+ raise ValueError(
1085
+ f"Liquid class definition not found for '{name}' version {version}."
1086
+ )
1087
+
1088
+ return LiquidClass.create(liquid_class_def)
1089
+
1090
+ def get_labware_location(
1091
+ self, labware_core: LabwareCore
1092
+ ) -> Union[str, LabwareCore, ModuleCore, NonConnectedModuleCore, OffDeckType]:
1093
+ """Get labware parent location."""
1094
+ labware_location = self._engine_client.state.labware.get_location(
1095
+ labware_core.labware_id
1096
+ )
1097
+ if isinstance(labware_location, DeckSlotLocation):
1098
+ return validation.internal_slot_to_public_string(
1099
+ labware_location.slotName, self._engine_client.state.config.robot_type
1100
+ )
1101
+ elif isinstance(labware_location, AddressableAreaLocation):
1102
+ # This will only ever be a robot accurate deck slot name or Flex staging slot name
1103
+ return labware_location.addressableAreaName
1104
+ elif isinstance(labware_location, ModuleLocation):
1105
+ return self._module_cores_by_id[labware_location.moduleId]
1106
+ elif isinstance(labware_location, OnLabwareLocation):
1107
+ return self._labware_cores_by_id[labware_location.labwareId]
1108
+
1109
+ return OffDeckType.OFF_DECK
1110
+
1111
+ def _convert_labware_location(
1112
+ self,
1113
+ location: Union[
1114
+ DeckSlotName,
1115
+ StagingSlotName,
1116
+ LabwareCore,
1117
+ ModuleCore,
1118
+ NonConnectedModuleCore,
1119
+ OffDeckType,
1120
+ WasteChute,
1121
+ TrashBin,
1122
+ ],
1123
+ ) -> LoadableLabwareLocation:
1124
+ if isinstance(location, LabwareCore):
1125
+ return OnLabwareLocation(labwareId=location.labware_id)
1126
+ else:
1127
+ return self._get_non_stacked_location(location)
1128
+
1129
+ @staticmethod
1130
+ def _get_non_stacked_location(
1131
+ location: Union[
1132
+ DeckSlotName,
1133
+ StagingSlotName,
1134
+ ModuleCore,
1135
+ NonConnectedModuleCore,
1136
+ OffDeckType,
1137
+ WasteChute,
1138
+ TrashBin,
1139
+ ],
1140
+ ) -> NonStackedLocation:
1141
+ if isinstance(location, (ModuleCore, NonConnectedModuleCore)):
1142
+ return ModuleLocation(moduleId=location.module_id)
1143
+ elif location is OffDeckType.OFF_DECK:
1144
+ return OFF_DECK_LOCATION
1145
+ elif isinstance(location, DeckSlotName):
1146
+ return DeckSlotLocation(slotName=location)
1147
+ elif isinstance(location, StagingSlotName):
1148
+ return AddressableAreaLocation(addressableAreaName=location.id)
1149
+ elif isinstance(location, WasteChute):
1150
+ # TODO(mm, 2023-12-06) This will need to determine the appropriate Waste Chute to return, but only move_labware uses this for now
1151
+ return AddressableAreaLocation(addressableAreaName="gripperWasteChute")
1152
+ elif isinstance(location, TrashBin):
1153
+ return AddressableAreaLocation(addressableAreaName=location.area_name)