opentrons 8.6.0a1__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 (600) 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 +501 -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 +183 -0
  45. opentrons/drivers/asyncio/communication/errors.py +88 -0
  46. opentrons/drivers/asyncio/communication/serial_connection.py +552 -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/simulator_setup.py +260 -0
  200. opentrons/hardware_control/thread_manager.py +431 -0
  201. opentrons/hardware_control/threaded_async_lock.py +97 -0
  202. opentrons/hardware_control/types.py +792 -0
  203. opentrons/hardware_control/util.py +234 -0
  204. opentrons/legacy_broker.py +53 -0
  205. opentrons/legacy_commands/__init__.py +1 -0
  206. opentrons/legacy_commands/commands.py +483 -0
  207. opentrons/legacy_commands/helpers.py +153 -0
  208. opentrons/legacy_commands/module_commands.py +215 -0
  209. opentrons/legacy_commands/protocol_commands.py +54 -0
  210. opentrons/legacy_commands/publisher.py +155 -0
  211. opentrons/legacy_commands/robot_commands.py +51 -0
  212. opentrons/legacy_commands/types.py +1115 -0
  213. opentrons/motion_planning/__init__.py +32 -0
  214. opentrons/motion_planning/adjacent_slots_getters.py +168 -0
  215. opentrons/motion_planning/deck_conflict.py +396 -0
  216. opentrons/motion_planning/errors.py +35 -0
  217. opentrons/motion_planning/types.py +42 -0
  218. opentrons/motion_planning/waypoints.py +218 -0
  219. opentrons/ordered_set.py +138 -0
  220. opentrons/protocol_api/__init__.py +105 -0
  221. opentrons/protocol_api/_liquid.py +157 -0
  222. opentrons/protocol_api/_liquid_properties.py +814 -0
  223. opentrons/protocol_api/_nozzle_layout.py +31 -0
  224. opentrons/protocol_api/_parameter_context.py +300 -0
  225. opentrons/protocol_api/_parameters.py +31 -0
  226. opentrons/protocol_api/_transfer_liquid_validation.py +108 -0
  227. opentrons/protocol_api/_types.py +43 -0
  228. opentrons/protocol_api/config.py +23 -0
  229. opentrons/protocol_api/core/__init__.py +23 -0
  230. opentrons/protocol_api/core/common.py +33 -0
  231. opentrons/protocol_api/core/core_map.py +74 -0
  232. opentrons/protocol_api/core/engine/__init__.py +22 -0
  233. opentrons/protocol_api/core/engine/_default_labware_versions.py +179 -0
  234. opentrons/protocol_api/core/engine/deck_conflict.py +348 -0
  235. opentrons/protocol_api/core/engine/exceptions.py +19 -0
  236. opentrons/protocol_api/core/engine/instrument.py +2391 -0
  237. opentrons/protocol_api/core/engine/labware.py +238 -0
  238. opentrons/protocol_api/core/engine/load_labware_params.py +73 -0
  239. opentrons/protocol_api/core/engine/module_core.py +1025 -0
  240. opentrons/protocol_api/core/engine/overlap_versions.py +20 -0
  241. opentrons/protocol_api/core/engine/pipette_movement_conflict.py +358 -0
  242. opentrons/protocol_api/core/engine/point_calculations.py +64 -0
  243. opentrons/protocol_api/core/engine/protocol.py +1153 -0
  244. opentrons/protocol_api/core/engine/robot.py +139 -0
  245. opentrons/protocol_api/core/engine/stringify.py +74 -0
  246. opentrons/protocol_api/core/engine/transfer_components_executor.py +990 -0
  247. opentrons/protocol_api/core/engine/well.py +241 -0
  248. opentrons/protocol_api/core/instrument.py +459 -0
  249. opentrons/protocol_api/core/labware.py +151 -0
  250. opentrons/protocol_api/core/legacy/__init__.py +11 -0
  251. opentrons/protocol_api/core/legacy/_labware_geometry.py +37 -0
  252. opentrons/protocol_api/core/legacy/deck.py +369 -0
  253. opentrons/protocol_api/core/legacy/labware_offset_provider.py +108 -0
  254. opentrons/protocol_api/core/legacy/legacy_instrument_core.py +709 -0
  255. opentrons/protocol_api/core/legacy/legacy_labware_core.py +235 -0
  256. opentrons/protocol_api/core/legacy/legacy_module_core.py +592 -0
  257. opentrons/protocol_api/core/legacy/legacy_protocol_core.py +612 -0
  258. opentrons/protocol_api/core/legacy/legacy_well_core.py +162 -0
  259. opentrons/protocol_api/core/legacy/load_info.py +67 -0
  260. opentrons/protocol_api/core/legacy/module_geometry.py +547 -0
  261. opentrons/protocol_api/core/legacy/well_geometry.py +148 -0
  262. opentrons/protocol_api/core/legacy_simulator/__init__.py +16 -0
  263. opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +624 -0
  264. opentrons/protocol_api/core/legacy_simulator/legacy_protocol_core.py +85 -0
  265. opentrons/protocol_api/core/module.py +484 -0
  266. opentrons/protocol_api/core/protocol.py +311 -0
  267. opentrons/protocol_api/core/robot.py +51 -0
  268. opentrons/protocol_api/core/well.py +116 -0
  269. opentrons/protocol_api/core/well_grid.py +45 -0
  270. opentrons/protocol_api/create_protocol_context.py +177 -0
  271. opentrons/protocol_api/deck.py +223 -0
  272. opentrons/protocol_api/disposal_locations.py +244 -0
  273. opentrons/protocol_api/instrument_context.py +3212 -0
  274. opentrons/protocol_api/labware.py +1579 -0
  275. opentrons/protocol_api/module_contexts.py +1425 -0
  276. opentrons/protocol_api/module_validation_and_errors.py +61 -0
  277. opentrons/protocol_api/protocol_context.py +1688 -0
  278. opentrons/protocol_api/robot_context.py +303 -0
  279. opentrons/protocol_api/validation.py +761 -0
  280. opentrons/protocol_engine/__init__.py +155 -0
  281. opentrons/protocol_engine/actions/__init__.py +65 -0
  282. opentrons/protocol_engine/actions/action_dispatcher.py +30 -0
  283. opentrons/protocol_engine/actions/action_handler.py +13 -0
  284. opentrons/protocol_engine/actions/actions.py +302 -0
  285. opentrons/protocol_engine/actions/get_state_update.py +38 -0
  286. opentrons/protocol_engine/clients/__init__.py +5 -0
  287. opentrons/protocol_engine/clients/sync_client.py +174 -0
  288. opentrons/protocol_engine/clients/transports.py +197 -0
  289. opentrons/protocol_engine/commands/__init__.py +757 -0
  290. opentrons/protocol_engine/commands/absorbance_reader/__init__.py +61 -0
  291. opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +154 -0
  292. opentrons/protocol_engine/commands/absorbance_reader/common.py +6 -0
  293. opentrons/protocol_engine/commands/absorbance_reader/initialize.py +151 -0
  294. opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +154 -0
  295. opentrons/protocol_engine/commands/absorbance_reader/read.py +226 -0
  296. opentrons/protocol_engine/commands/air_gap_in_place.py +162 -0
  297. opentrons/protocol_engine/commands/aspirate.py +244 -0
  298. opentrons/protocol_engine/commands/aspirate_in_place.py +184 -0
  299. opentrons/protocol_engine/commands/aspirate_while_tracking.py +211 -0
  300. opentrons/protocol_engine/commands/blow_out.py +146 -0
  301. opentrons/protocol_engine/commands/blow_out_in_place.py +119 -0
  302. opentrons/protocol_engine/commands/calibration/__init__.py +60 -0
  303. opentrons/protocol_engine/commands/calibration/calibrate_gripper.py +166 -0
  304. opentrons/protocol_engine/commands/calibration/calibrate_module.py +117 -0
  305. opentrons/protocol_engine/commands/calibration/calibrate_pipette.py +96 -0
  306. opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py +156 -0
  307. opentrons/protocol_engine/commands/command.py +308 -0
  308. opentrons/protocol_engine/commands/command_unions.py +974 -0
  309. opentrons/protocol_engine/commands/comment.py +57 -0
  310. opentrons/protocol_engine/commands/configure_for_volume.py +108 -0
  311. opentrons/protocol_engine/commands/configure_nozzle_layout.py +115 -0
  312. opentrons/protocol_engine/commands/custom.py +67 -0
  313. opentrons/protocol_engine/commands/dispense.py +194 -0
  314. opentrons/protocol_engine/commands/dispense_in_place.py +179 -0
  315. opentrons/protocol_engine/commands/dispense_while_tracking.py +204 -0
  316. opentrons/protocol_engine/commands/drop_tip.py +232 -0
  317. opentrons/protocol_engine/commands/drop_tip_in_place.py +205 -0
  318. opentrons/protocol_engine/commands/flex_stacker/__init__.py +64 -0
  319. opentrons/protocol_engine/commands/flex_stacker/common.py +900 -0
  320. opentrons/protocol_engine/commands/flex_stacker/empty.py +293 -0
  321. opentrons/protocol_engine/commands/flex_stacker/fill.py +281 -0
  322. opentrons/protocol_engine/commands/flex_stacker/retrieve.py +339 -0
  323. opentrons/protocol_engine/commands/flex_stacker/set_stored_labware.py +328 -0
  324. opentrons/protocol_engine/commands/flex_stacker/store.py +326 -0
  325. opentrons/protocol_engine/commands/generate_command_schema.py +61 -0
  326. opentrons/protocol_engine/commands/get_next_tip.py +134 -0
  327. opentrons/protocol_engine/commands/get_tip_presence.py +87 -0
  328. opentrons/protocol_engine/commands/hash_command_params.py +38 -0
  329. opentrons/protocol_engine/commands/heater_shaker/__init__.py +102 -0
  330. opentrons/protocol_engine/commands/heater_shaker/close_labware_latch.py +83 -0
  331. opentrons/protocol_engine/commands/heater_shaker/deactivate_heater.py +82 -0
  332. opentrons/protocol_engine/commands/heater_shaker/deactivate_shaker.py +84 -0
  333. opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py +110 -0
  334. opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +125 -0
  335. opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +90 -0
  336. opentrons/protocol_engine/commands/heater_shaker/wait_for_temperature.py +102 -0
  337. opentrons/protocol_engine/commands/home.py +100 -0
  338. opentrons/protocol_engine/commands/identify_module.py +86 -0
  339. opentrons/protocol_engine/commands/labware_handling_common.py +29 -0
  340. opentrons/protocol_engine/commands/liquid_probe.py +464 -0
  341. opentrons/protocol_engine/commands/load_labware.py +210 -0
  342. opentrons/protocol_engine/commands/load_lid.py +154 -0
  343. opentrons/protocol_engine/commands/load_lid_stack.py +272 -0
  344. opentrons/protocol_engine/commands/load_liquid.py +95 -0
  345. opentrons/protocol_engine/commands/load_liquid_class.py +144 -0
  346. opentrons/protocol_engine/commands/load_module.py +223 -0
  347. opentrons/protocol_engine/commands/load_pipette.py +167 -0
  348. opentrons/protocol_engine/commands/magnetic_module/__init__.py +32 -0
  349. opentrons/protocol_engine/commands/magnetic_module/disengage.py +97 -0
  350. opentrons/protocol_engine/commands/magnetic_module/engage.py +119 -0
  351. opentrons/protocol_engine/commands/move_labware.py +546 -0
  352. opentrons/protocol_engine/commands/move_relative.py +102 -0
  353. opentrons/protocol_engine/commands/move_to_addressable_area.py +176 -0
  354. opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py +198 -0
  355. opentrons/protocol_engine/commands/move_to_coordinates.py +107 -0
  356. opentrons/protocol_engine/commands/move_to_well.py +119 -0
  357. opentrons/protocol_engine/commands/movement_common.py +338 -0
  358. opentrons/protocol_engine/commands/pick_up_tip.py +241 -0
  359. opentrons/protocol_engine/commands/pipetting_common.py +443 -0
  360. opentrons/protocol_engine/commands/prepare_to_aspirate.py +121 -0
  361. opentrons/protocol_engine/commands/pressure_dispense.py +155 -0
  362. opentrons/protocol_engine/commands/reload_labware.py +90 -0
  363. opentrons/protocol_engine/commands/retract_axis.py +75 -0
  364. opentrons/protocol_engine/commands/robot/__init__.py +70 -0
  365. opentrons/protocol_engine/commands/robot/close_gripper_jaw.py +96 -0
  366. opentrons/protocol_engine/commands/robot/common.py +18 -0
  367. opentrons/protocol_engine/commands/robot/move_axes_relative.py +101 -0
  368. opentrons/protocol_engine/commands/robot/move_axes_to.py +100 -0
  369. opentrons/protocol_engine/commands/robot/move_to.py +94 -0
  370. opentrons/protocol_engine/commands/robot/open_gripper_jaw.py +86 -0
  371. opentrons/protocol_engine/commands/save_position.py +109 -0
  372. opentrons/protocol_engine/commands/seal_pipette_to_tip.py +353 -0
  373. opentrons/protocol_engine/commands/set_rail_lights.py +67 -0
  374. opentrons/protocol_engine/commands/set_status_bar.py +89 -0
  375. opentrons/protocol_engine/commands/temperature_module/__init__.py +46 -0
  376. opentrons/protocol_engine/commands/temperature_module/deactivate.py +86 -0
  377. opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +97 -0
  378. opentrons/protocol_engine/commands/temperature_module/wait_for_temperature.py +104 -0
  379. opentrons/protocol_engine/commands/thermocycler/__init__.py +152 -0
  380. opentrons/protocol_engine/commands/thermocycler/close_lid.py +87 -0
  381. opentrons/protocol_engine/commands/thermocycler/deactivate_block.py +80 -0
  382. opentrons/protocol_engine/commands/thermocycler/deactivate_lid.py +80 -0
  383. opentrons/protocol_engine/commands/thermocycler/open_lid.py +87 -0
  384. opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +171 -0
  385. opentrons/protocol_engine/commands/thermocycler/run_profile.py +124 -0
  386. opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +140 -0
  387. opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +100 -0
  388. opentrons/protocol_engine/commands/thermocycler/wait_for_block_temperature.py +93 -0
  389. opentrons/protocol_engine/commands/thermocycler/wait_for_lid_temperature.py +89 -0
  390. opentrons/protocol_engine/commands/touch_tip.py +189 -0
  391. opentrons/protocol_engine/commands/unsafe/__init__.py +161 -0
  392. opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +100 -0
  393. opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +121 -0
  394. opentrons/protocol_engine/commands/unsafe/unsafe_engage_axes.py +82 -0
  395. opentrons/protocol_engine/commands/unsafe/unsafe_place_labware.py +208 -0
  396. opentrons/protocol_engine/commands/unsafe/unsafe_stacker_close_latch.py +94 -0
  397. opentrons/protocol_engine/commands/unsafe/unsafe_stacker_manual_retrieve.py +295 -0
  398. opentrons/protocol_engine/commands/unsafe/unsafe_stacker_open_latch.py +91 -0
  399. opentrons/protocol_engine/commands/unsafe/unsafe_stacker_prepare_shuttle.py +136 -0
  400. opentrons/protocol_engine/commands/unsafe/unsafe_ungrip_labware.py +77 -0
  401. opentrons/protocol_engine/commands/unsafe/update_position_estimators.py +90 -0
  402. opentrons/protocol_engine/commands/unseal_pipette_from_tip.py +153 -0
  403. opentrons/protocol_engine/commands/verify_tip_presence.py +100 -0
  404. opentrons/protocol_engine/commands/wait_for_duration.py +76 -0
  405. opentrons/protocol_engine/commands/wait_for_resume.py +75 -0
  406. opentrons/protocol_engine/create_protocol_engine.py +193 -0
  407. opentrons/protocol_engine/engine_support.py +28 -0
  408. opentrons/protocol_engine/error_recovery_policy.py +81 -0
  409. opentrons/protocol_engine/errors/__init__.py +191 -0
  410. opentrons/protocol_engine/errors/error_occurrence.py +182 -0
  411. opentrons/protocol_engine/errors/exceptions.py +1308 -0
  412. opentrons/protocol_engine/execution/__init__.py +50 -0
  413. opentrons/protocol_engine/execution/command_executor.py +216 -0
  414. opentrons/protocol_engine/execution/create_queue_worker.py +102 -0
  415. opentrons/protocol_engine/execution/door_watcher.py +119 -0
  416. opentrons/protocol_engine/execution/equipment.py +819 -0
  417. opentrons/protocol_engine/execution/error_recovery_hardware_state_synchronizer.py +101 -0
  418. opentrons/protocol_engine/execution/gantry_mover.py +686 -0
  419. opentrons/protocol_engine/execution/hardware_stopper.py +147 -0
  420. opentrons/protocol_engine/execution/heater_shaker_movement_flagger.py +207 -0
  421. opentrons/protocol_engine/execution/labware_movement.py +297 -0
  422. opentrons/protocol_engine/execution/movement.py +349 -0
  423. opentrons/protocol_engine/execution/pipetting.py +607 -0
  424. opentrons/protocol_engine/execution/queue_worker.py +86 -0
  425. opentrons/protocol_engine/execution/rail_lights.py +25 -0
  426. opentrons/protocol_engine/execution/run_control.py +33 -0
  427. opentrons/protocol_engine/execution/status_bar.py +34 -0
  428. opentrons/protocol_engine/execution/thermocycler_movement_flagger.py +188 -0
  429. opentrons/protocol_engine/execution/thermocycler_plate_lifter.py +81 -0
  430. opentrons/protocol_engine/execution/tip_handler.py +550 -0
  431. opentrons/protocol_engine/labware_offset_standardization.py +194 -0
  432. opentrons/protocol_engine/notes/__init__.py +17 -0
  433. opentrons/protocol_engine/notes/notes.py +59 -0
  434. opentrons/protocol_engine/plugins.py +104 -0
  435. opentrons/protocol_engine/protocol_engine.py +683 -0
  436. opentrons/protocol_engine/resources/__init__.py +26 -0
  437. opentrons/protocol_engine/resources/deck_configuration_provider.py +232 -0
  438. opentrons/protocol_engine/resources/deck_data_provider.py +94 -0
  439. opentrons/protocol_engine/resources/file_provider.py +161 -0
  440. opentrons/protocol_engine/resources/fixture_validation.py +58 -0
  441. opentrons/protocol_engine/resources/labware_data_provider.py +106 -0
  442. opentrons/protocol_engine/resources/labware_validation.py +73 -0
  443. opentrons/protocol_engine/resources/model_utils.py +32 -0
  444. opentrons/protocol_engine/resources/module_data_provider.py +44 -0
  445. opentrons/protocol_engine/resources/ot3_validation.py +21 -0
  446. opentrons/protocol_engine/resources/pipette_data_provider.py +379 -0
  447. opentrons/protocol_engine/slot_standardization.py +128 -0
  448. opentrons/protocol_engine/state/__init__.py +1 -0
  449. opentrons/protocol_engine/state/_abstract_store.py +27 -0
  450. opentrons/protocol_engine/state/_axis_aligned_bounding_box.py +50 -0
  451. opentrons/protocol_engine/state/_labware_origin_math.py +636 -0
  452. opentrons/protocol_engine/state/_move_types.py +83 -0
  453. opentrons/protocol_engine/state/_well_math.py +193 -0
  454. opentrons/protocol_engine/state/addressable_areas.py +699 -0
  455. opentrons/protocol_engine/state/command_history.py +309 -0
  456. opentrons/protocol_engine/state/commands.py +1158 -0
  457. opentrons/protocol_engine/state/config.py +39 -0
  458. opentrons/protocol_engine/state/files.py +57 -0
  459. opentrons/protocol_engine/state/fluid_stack.py +138 -0
  460. opentrons/protocol_engine/state/geometry.py +2359 -0
  461. opentrons/protocol_engine/state/inner_well_math_utils.py +548 -0
  462. opentrons/protocol_engine/state/labware.py +1459 -0
  463. opentrons/protocol_engine/state/liquid_classes.py +82 -0
  464. opentrons/protocol_engine/state/liquids.py +73 -0
  465. opentrons/protocol_engine/state/module_substates/__init__.py +45 -0
  466. opentrons/protocol_engine/state/module_substates/absorbance_reader_substate.py +35 -0
  467. opentrons/protocol_engine/state/module_substates/flex_stacker_substate.py +112 -0
  468. opentrons/protocol_engine/state/module_substates/heater_shaker_module_substate.py +115 -0
  469. opentrons/protocol_engine/state/module_substates/magnetic_block_substate.py +17 -0
  470. opentrons/protocol_engine/state/module_substates/magnetic_module_substate.py +65 -0
  471. opentrons/protocol_engine/state/module_substates/temperature_module_substate.py +67 -0
  472. opentrons/protocol_engine/state/module_substates/thermocycler_module_substate.py +163 -0
  473. opentrons/protocol_engine/state/modules.py +1500 -0
  474. opentrons/protocol_engine/state/motion.py +373 -0
  475. opentrons/protocol_engine/state/pipettes.py +905 -0
  476. opentrons/protocol_engine/state/state.py +421 -0
  477. opentrons/protocol_engine/state/state_summary.py +36 -0
  478. opentrons/protocol_engine/state/tips.py +420 -0
  479. opentrons/protocol_engine/state/update_types.py +904 -0
  480. opentrons/protocol_engine/state/wells.py +290 -0
  481. opentrons/protocol_engine/types/__init__.py +308 -0
  482. opentrons/protocol_engine/types/automatic_tip_selection.py +39 -0
  483. opentrons/protocol_engine/types/command_annotations.py +53 -0
  484. opentrons/protocol_engine/types/deck_configuration.py +81 -0
  485. opentrons/protocol_engine/types/execution.py +96 -0
  486. opentrons/protocol_engine/types/hardware_passthrough.py +25 -0
  487. opentrons/protocol_engine/types/instrument.py +47 -0
  488. opentrons/protocol_engine/types/instrument_sensors.py +47 -0
  489. opentrons/protocol_engine/types/labware.py +131 -0
  490. opentrons/protocol_engine/types/labware_movement.py +22 -0
  491. opentrons/protocol_engine/types/labware_offset_location.py +111 -0
  492. opentrons/protocol_engine/types/labware_offset_vector.py +16 -0
  493. opentrons/protocol_engine/types/liquid.py +40 -0
  494. opentrons/protocol_engine/types/liquid_class.py +59 -0
  495. opentrons/protocol_engine/types/liquid_handling.py +13 -0
  496. opentrons/protocol_engine/types/liquid_level_detection.py +191 -0
  497. opentrons/protocol_engine/types/location.py +194 -0
  498. opentrons/protocol_engine/types/module.py +303 -0
  499. opentrons/protocol_engine/types/partial_tip_configuration.py +76 -0
  500. opentrons/protocol_engine/types/run_time_parameters.py +133 -0
  501. opentrons/protocol_engine/types/tip.py +18 -0
  502. opentrons/protocol_engine/types/util.py +21 -0
  503. opentrons/protocol_engine/types/well_position.py +124 -0
  504. opentrons/protocol_reader/__init__.py +37 -0
  505. opentrons/protocol_reader/extract_labware_definitions.py +66 -0
  506. opentrons/protocol_reader/file_format_validator.py +152 -0
  507. opentrons/protocol_reader/file_hasher.py +27 -0
  508. opentrons/protocol_reader/file_identifier.py +284 -0
  509. opentrons/protocol_reader/file_reader_writer.py +90 -0
  510. opentrons/protocol_reader/input_file.py +16 -0
  511. opentrons/protocol_reader/protocol_files_invalid_error.py +6 -0
  512. opentrons/protocol_reader/protocol_reader.py +188 -0
  513. opentrons/protocol_reader/protocol_source.py +124 -0
  514. opentrons/protocol_reader/role_analyzer.py +86 -0
  515. opentrons/protocol_runner/__init__.py +26 -0
  516. opentrons/protocol_runner/create_simulating_orchestrator.py +118 -0
  517. opentrons/protocol_runner/json_file_reader.py +55 -0
  518. opentrons/protocol_runner/json_translator.py +314 -0
  519. opentrons/protocol_runner/legacy_command_mapper.py +848 -0
  520. opentrons/protocol_runner/legacy_context_plugin.py +116 -0
  521. opentrons/protocol_runner/protocol_runner.py +530 -0
  522. opentrons/protocol_runner/python_protocol_wrappers.py +179 -0
  523. opentrons/protocol_runner/run_orchestrator.py +496 -0
  524. opentrons/protocol_runner/task_queue.py +95 -0
  525. opentrons/protocols/__init__.py +6 -0
  526. opentrons/protocols/advanced_control/__init__.py +0 -0
  527. opentrons/protocols/advanced_control/common.py +38 -0
  528. opentrons/protocols/advanced_control/mix.py +60 -0
  529. opentrons/protocols/advanced_control/transfers/__init__.py +0 -0
  530. opentrons/protocols/advanced_control/transfers/common.py +180 -0
  531. opentrons/protocols/advanced_control/transfers/transfer.py +972 -0
  532. opentrons/protocols/advanced_control/transfers/transfer_liquid_utils.py +231 -0
  533. opentrons/protocols/api_support/__init__.py +0 -0
  534. opentrons/protocols/api_support/constants.py +8 -0
  535. opentrons/protocols/api_support/deck_type.py +110 -0
  536. opentrons/protocols/api_support/definitions.py +18 -0
  537. opentrons/protocols/api_support/instrument.py +151 -0
  538. opentrons/protocols/api_support/labware_like.py +233 -0
  539. opentrons/protocols/api_support/tip_tracker.py +175 -0
  540. opentrons/protocols/api_support/types.py +32 -0
  541. opentrons/protocols/api_support/util.py +403 -0
  542. opentrons/protocols/bundle.py +89 -0
  543. opentrons/protocols/duration/__init__.py +4 -0
  544. opentrons/protocols/duration/errors.py +5 -0
  545. opentrons/protocols/duration/estimator.py +628 -0
  546. opentrons/protocols/execution/__init__.py +0 -0
  547. opentrons/protocols/execution/dev_types.py +181 -0
  548. opentrons/protocols/execution/errors.py +40 -0
  549. opentrons/protocols/execution/execute.py +84 -0
  550. opentrons/protocols/execution/execute_json_v3.py +275 -0
  551. opentrons/protocols/execution/execute_json_v4.py +359 -0
  552. opentrons/protocols/execution/execute_json_v5.py +28 -0
  553. opentrons/protocols/execution/execute_python.py +169 -0
  554. opentrons/protocols/execution/json_dispatchers.py +87 -0
  555. opentrons/protocols/execution/types.py +7 -0
  556. opentrons/protocols/geometry/__init__.py +0 -0
  557. opentrons/protocols/geometry/planning.py +297 -0
  558. opentrons/protocols/labware.py +312 -0
  559. opentrons/protocols/models/__init__.py +0 -0
  560. opentrons/protocols/models/json_protocol.py +679 -0
  561. opentrons/protocols/parameters/__init__.py +0 -0
  562. opentrons/protocols/parameters/csv_parameter_definition.py +77 -0
  563. opentrons/protocols/parameters/csv_parameter_interface.py +96 -0
  564. opentrons/protocols/parameters/exceptions.py +34 -0
  565. opentrons/protocols/parameters/parameter_definition.py +272 -0
  566. opentrons/protocols/parameters/types.py +17 -0
  567. opentrons/protocols/parameters/validation.py +267 -0
  568. opentrons/protocols/parse.py +671 -0
  569. opentrons/protocols/types.py +159 -0
  570. opentrons/py.typed +0 -0
  571. opentrons/resources/scripts/lpc21isp +0 -0
  572. opentrons/resources/smoothie-edge-8414642.hex +23010 -0
  573. opentrons/simulate.py +1065 -0
  574. opentrons/system/__init__.py +6 -0
  575. opentrons/system/camera.py +51 -0
  576. opentrons/system/log_control.py +59 -0
  577. opentrons/system/nmcli.py +856 -0
  578. opentrons/system/resin.py +24 -0
  579. opentrons/system/smoothie_update.py +15 -0
  580. opentrons/system/wifi.py +204 -0
  581. opentrons/tools/__init__.py +0 -0
  582. opentrons/tools/args_handler.py +22 -0
  583. opentrons/tools/write_pipette_memory.py +157 -0
  584. opentrons/types.py +618 -0
  585. opentrons/util/__init__.py +1 -0
  586. opentrons/util/async_helpers.py +166 -0
  587. opentrons/util/broker.py +84 -0
  588. opentrons/util/change_notifier.py +47 -0
  589. opentrons/util/entrypoint_util.py +278 -0
  590. opentrons/util/get_union_elements.py +26 -0
  591. opentrons/util/helpers.py +6 -0
  592. opentrons/util/linal.py +178 -0
  593. opentrons/util/logging_config.py +265 -0
  594. opentrons/util/logging_queue_handler.py +61 -0
  595. opentrons/util/performance_helpers.py +157 -0
  596. opentrons-8.6.0a1.dist-info/METADATA +37 -0
  597. opentrons-8.6.0a1.dist-info/RECORD +600 -0
  598. opentrons-8.6.0a1.dist-info/WHEEL +4 -0
  599. opentrons-8.6.0a1.dist-info/entry_points.txt +3 -0
  600. opentrons-8.6.0a1.dist-info/licenses/LICENSE +202 -0
@@ -0,0 +1,31 @@
1
+ from typing import List
2
+
3
+ from typing_extensions import Literal
4
+
5
+ from pydantic import BaseModel, Field
6
+
7
+
8
+ class ModuleConnection(BaseModel):
9
+ """Model a single module connection."""
10
+
11
+ url: str = Field(
12
+ ...,
13
+ description="The url (port) value the module driver should connect to. "
14
+ "For example: socket://host:port",
15
+ )
16
+ module_type: str = Field(
17
+ ..., description="What kind of module this connection emulates."
18
+ )
19
+ identifier: str = Field(..., description="Unique id for this emulator.")
20
+
21
+
22
+ class Message(BaseModel):
23
+ """A message sent to module server clients."""
24
+
25
+ status: Literal["connected", "disconnected", "dump"] = Field(
26
+ ...,
27
+ description="`dump` includes a complete list of connected emulators. "
28
+ "`connected` for new connections. `disconnected` for emulators "
29
+ "that have disconnected. ",
30
+ )
31
+ connections: List[ModuleConnection]
@@ -0,0 +1,110 @@
1
+ """Server notifying of module connections."""
2
+ import asyncio
3
+ import logging
4
+ from typing import Dict, Set
5
+
6
+ from opentrons.hardware_control.emulation.module_server.models import (
7
+ ModuleConnection,
8
+ Message,
9
+ )
10
+ from opentrons.hardware_control.emulation.proxy import ProxyListener
11
+ from opentrons.hardware_control.emulation.settings import ModuleServerSettings
12
+ from typing_extensions import Final
13
+
14
+ log = logging.getLogger(__name__)
15
+
16
+ MessageDelimiter: Final = b"\n"
17
+
18
+
19
+ class ModuleStatusServer(ProxyListener):
20
+ """The module status server is the emulator equivalent of inotify. A client
21
+ can know when an emulated module connects or disconnects.
22
+
23
+ Clients connect and read JSON messages (See models module).
24
+ """
25
+
26
+ def __init__(self, settings: ModuleServerSettings) -> None:
27
+ """Constructor
28
+
29
+ Args:
30
+ settings: app settings
31
+ """
32
+ self._settings = settings
33
+ self._connections: Dict[str, ModuleConnection] = {}
34
+ self._clients: Set[asyncio.StreamWriter] = set()
35
+
36
+ def on_server_connected(
37
+ self, server_type: str, client_uri: str, identifier: str
38
+ ) -> None:
39
+ """Called when a new module has connected.
40
+
41
+ Args:
42
+ server_type: the type of module
43
+ client_uri: the url string for a driver to connect to
44
+ identifier: unique id for connection
45
+
46
+ Returns: None
47
+
48
+ """
49
+ log.info(f"On connected {server_type} {client_uri} {identifier}")
50
+ connection = ModuleConnection(
51
+ module_type=server_type, url=client_uri, identifier=identifier
52
+ )
53
+ self._connections[identifier] = connection
54
+ for c in self._clients:
55
+ c.write(
56
+ Message(status="connected", connections=[connection])
57
+ .model_dump_json()
58
+ .encode()
59
+ )
60
+ c.write(b"\n")
61
+
62
+ def on_server_disconnected(self, identifier: str) -> None:
63
+ """Called when a module has disconnected.
64
+
65
+ Args:
66
+ identifier: unique id for the connection
67
+
68
+ Returns: None
69
+ """
70
+ log.info(f"On disconnected {identifier}")
71
+ try:
72
+ connection = self._connections[identifier]
73
+ del self._connections[identifier]
74
+ for c in self._clients:
75
+ c.write(
76
+ Message(status="disconnected", connections=[connection])
77
+ .model_dump_json()
78
+ .encode()
79
+ )
80
+ c.write(MessageDelimiter)
81
+ except KeyError:
82
+ log.exception("Failed to find identifier")
83
+
84
+ async def run(self) -> None:
85
+ """Run the server."""
86
+ server = await asyncio.start_server(
87
+ self._handle_connection, host=self._settings.host, port=self._settings.port
88
+ )
89
+ await server.serve_forever()
90
+
91
+ async def _handle_connection(
92
+ self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter
93
+ ) -> None:
94
+ """Handle a client connection to the server."""
95
+ log.info("Client connected to module server.")
96
+
97
+ # A client connected. Send a dump of all connected modules.
98
+ m = Message(status="dump", connections=list(self._connections.values()))
99
+
100
+ writer.write(m.model_dump_json().encode())
101
+ writer.write(MessageDelimiter)
102
+
103
+ self._clients.add(writer)
104
+
105
+ while True:
106
+ if b"" == await reader.read():
107
+ self._clients.remove(writer)
108
+ break
109
+
110
+ log.info("Client disconnected from module server.")
@@ -0,0 +1,74 @@
1
+ import re
2
+ from dataclasses import dataclass
3
+ from typing import Dict, Generator, Optional
4
+
5
+
6
+ @dataclass
7
+ class Command:
8
+ gcode: str
9
+ body: str
10
+ params: Dict[str, Optional[float]]
11
+
12
+
13
+ class Parser:
14
+ """Gcode line parser."""
15
+
16
+ # TODO (al, 2021-05-11): Should G01 and G1 be treated differently? Currently
17
+ # they are two different Gcodes.
18
+ GCODE_RE = re.compile(r"(?:(?:[MG]\d+\.?\d*)|dfu|version)")
19
+ """A gcode is either M or G followed by decimal. Or 'dfu' or 'version'."""
20
+ ALPHA_PREFIXED_NUMBER_RE = re.compile(r"(?P<prefix>[A-Z])(?P<number>-?\d*\.?\d*)")
21
+ """All parameters are a capital letter followed by a decimal value."""
22
+
23
+ def parse(self, line: str) -> Generator[Command, None, None]:
24
+ """
25
+ Parse a line to extract commands.
26
+
27
+ Args:
28
+ line: a line containing gcodes and their values. spaces are optional.
29
+
30
+ Returns:
31
+ Command object
32
+ """
33
+ line = line.strip()
34
+ previous = None
35
+ for i in self.GCODE_RE.finditer(line):
36
+ if previous:
37
+ yield self._create_command(
38
+ line[previous.start() : previous.end()],
39
+ line[previous.end() : i.start()],
40
+ )
41
+ else:
42
+ # This is the first match. It better be at the beginning or
43
+ # there's junk in the beginning.
44
+ if i.start() != 0:
45
+ raise ValueError(f"Invalid content: {line}")
46
+ previous = i
47
+ if previous:
48
+ # Create command from final GCODE and remainder of the line.
49
+ yield self._create_command(
50
+ line[previous.start() : previous.end()], line[previous.end() :]
51
+ )
52
+ elif line:
53
+ # There are no GCODEs and it's a non-empty line.
54
+ raise ValueError(f"Invalid content: {line}")
55
+
56
+ @staticmethod
57
+ def _create_command(gcode: str, body: str) -> Command:
58
+ """
59
+ Create a Command.
60
+
61
+ Args:
62
+ gcode: the gcode
63
+ body: the parameter string
64
+
65
+ Returns: a Command object
66
+ """
67
+ pars = (i.groupdict() for i in Parser.ALPHA_PREFIXED_NUMBER_RE.finditer(body))
68
+ return Command(
69
+ gcode=gcode,
70
+ body=body.strip(),
71
+ params={
72
+ p["prefix"]: float(p["number"]) if p["number"] else None for p in pars
73
+ },
74
+ )
@@ -0,0 +1,241 @@
1
+ """The Proxy class module."""
2
+ from __future__ import annotations
3
+ import asyncio
4
+ import logging
5
+ import uuid
6
+ import socket
7
+ from abc import ABC, abstractmethod
8
+ from dataclasses import dataclass
9
+ from typing import List
10
+
11
+ from opentrons.hardware_control.emulation.settings import ProxySettings
12
+
13
+ log = logging.getLogger(__name__)
14
+
15
+
16
+ @dataclass(frozen=True)
17
+ class Connection:
18
+ """Attributes of a client connected on the server port (module emulator)."""
19
+
20
+ identifier: str
21
+ reader: asyncio.StreamReader
22
+ writer: asyncio.StreamWriter
23
+
24
+
25
+ class ProxyListener(ABC):
26
+ """Interface defining an object needing to know when a server (module emulator)
27
+ connected/disconnected."""
28
+
29
+ @abstractmethod
30
+ def on_server_connected(
31
+ self, server_type: str, client_uri: str, identifier: str
32
+ ) -> None:
33
+ """Called when a new server connects."""
34
+ ...
35
+
36
+ @abstractmethod
37
+ def on_server_disconnected(self, identifier: str) -> None:
38
+ """Called when a server disconnects."""
39
+ ...
40
+
41
+
42
+ class Proxy:
43
+ """A class that has servers (emulators) connect on one port and clients
44
+ (drivers) on another. A server connection will be added to a collection. A
45
+ client connection will check for a server connection and if available will
46
+ have its write stream attached to the servers read stream and vice versa."""
47
+
48
+ def __init__(
49
+ self, name: str, listener: ProxyListener, settings: ProxySettings
50
+ ) -> None:
51
+ """Constructor.
52
+
53
+ Args:
54
+ name: Proxy name.
55
+ listener: Connection even listener.
56
+ settings: The proxy settings.
57
+ """
58
+ self._name = name
59
+ self._settings = settings
60
+ self._event_listener = listener
61
+ self._cons: List[Connection] = []
62
+
63
+ @property
64
+ def name(self) -> str:
65
+ """Return the name of the proxy."""
66
+ return self._name
67
+
68
+ async def run(self) -> None:
69
+ """Run the server."""
70
+ await asyncio.gather(
71
+ self._listen_server_connections(),
72
+ self._listen_client_connections(),
73
+ )
74
+
75
+ async def _listen_server_connections(self) -> None:
76
+ """Run the server listener."""
77
+ log.info(
78
+ f"starting {self._name} server connection server at "
79
+ f"{self._settings.host}:{self._settings.emulator_port}"
80
+ )
81
+ server = await asyncio.start_server(
82
+ self._handle_server_connection,
83
+ self._settings.host,
84
+ self._settings.emulator_port,
85
+ )
86
+ await server.serve_forever()
87
+
88
+ async def _listen_client_connections(self) -> None:
89
+ """Run the client listener."""
90
+ log.info(
91
+ f"starting {self._name} client connection server at "
92
+ f"{self._settings.host}:{self._settings.driver_port}"
93
+ )
94
+ server = await asyncio.start_server(
95
+ self._handle_client_connection,
96
+ self._settings.host,
97
+ self._settings.driver_port,
98
+ )
99
+ await server.serve_forever()
100
+
101
+ async def _handle_server_connection(
102
+ self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter
103
+ ) -> None:
104
+ """Handle a server connection.
105
+
106
+ A new connection will be added to the our connection collection.
107
+
108
+ Args:
109
+ reader: Reader
110
+ writer: Writer
111
+
112
+ Returns:
113
+ None
114
+ """
115
+ log.info(f"{self._name} emulator connected.")
116
+ connection = Connection(
117
+ identifier=str(uuid.uuid1()), reader=reader, writer=writer
118
+ )
119
+
120
+ log.info(f"Using Local Host: {self._settings.use_local_host}")
121
+
122
+ client_host = (
123
+ "127.0.0.1" if self._settings.use_local_host else socket.gethostname()
124
+ )
125
+
126
+ self._cons.append(connection)
127
+ self._event_listener.on_server_connected(
128
+ server_type=self._name,
129
+ client_uri=f"socket://{client_host}:{self._settings.driver_port}",
130
+ identifier=connection.identifier,
131
+ )
132
+
133
+ async def _handle_client_connection(
134
+ self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter
135
+ ) -> None:
136
+ """Handle a client connection.
137
+
138
+ Attempt to match the client steam with an available server stream.
139
+
140
+ Args:
141
+ reader: Reader
142
+ writer: Writer
143
+
144
+ Returns:
145
+ None
146
+ """
147
+ try:
148
+ while True:
149
+ # Pop an emulator connection.
150
+ connection = self._cons.pop(0)
151
+ if not connection.reader.at_eof():
152
+ break
153
+ else:
154
+ log.info(f"{self._name} server connection terminated")
155
+ self._event_listener.on_server_disconnected(connection.identifier)
156
+ except IndexError:
157
+ log.info(f"{self._name} no emulator connected.")
158
+ writer.close()
159
+ return
160
+
161
+ log.info(
162
+ f"{self._name} "
163
+ f"client at {writer.transport.get_extra_info('socket')}"
164
+ f" connected to {connection.writer.transport.get_extra_info('socket')}."
165
+ )
166
+
167
+ await self._handle_proxy(
168
+ driver=Connection(
169
+ reader=reader, writer=writer, identifier=connection.identifier
170
+ ),
171
+ server=connection,
172
+ )
173
+
174
+ # Return the emulator connection to the pool.
175
+ if not connection.reader.at_eof():
176
+ log.info(f"{self._name} returning connection to pool")
177
+ self._cons.append(connection)
178
+ else:
179
+ log.info(f"{self._name} server connection terminated")
180
+ self._event_listener.on_server_disconnected(connection.identifier)
181
+
182
+ async def _handle_proxy(self, driver: Connection, server: Connection) -> None:
183
+ """Connect the driver to the emulator.
184
+
185
+ Args:
186
+ driver: Driver connection
187
+ server: Emulator connection
188
+
189
+ Returns:
190
+ None
191
+ """
192
+ loop = asyncio.get_event_loop()
193
+ read_from_client_task = loop.create_task(
194
+ self._data_router(driver, server, False)
195
+ )
196
+ read_from_server_task = loop.create_task(
197
+ self._data_router(server, driver, True)
198
+ )
199
+ await read_from_client_task
200
+ read_from_server_task.cancel()
201
+ try:
202
+ await read_from_server_task
203
+ except asyncio.CancelledError:
204
+ log.exception("Server task cancelled")
205
+ pass
206
+
207
+ @staticmethod
208
+ async def _data_router(
209
+ in_connection: Connection,
210
+ out_connection: Connection,
211
+ close_other_on_disconnect: bool,
212
+ ) -> None:
213
+ """Route date from in to out.
214
+
215
+ Args:
216
+ in_connection: connection to read from.
217
+ out_connection: connection to write to
218
+ close_other_on_disconnect: whether the other connection should
219
+ be closed if the in_connection is closed.
220
+ A driver disconnect should close connection with emulator, while
221
+ an emulator disconnect should close the attached driver.
222
+
223
+ Returns:
224
+ None
225
+ """
226
+ while True:
227
+ try:
228
+ d = await in_connection.reader.read(1)
229
+ out_connection.writer.write(d)
230
+
231
+ if not d:
232
+ log.info(
233
+ f"{in_connection.writer.transport.get_extra_info('socket')} "
234
+ f"disconnected."
235
+ )
236
+ break
237
+ except ConnectionError:
238
+ log.exception("connection error in data router")
239
+ break
240
+ if close_other_on_disconnect:
241
+ out_connection.writer.close()
@@ -0,0 +1,68 @@
1
+ import asyncio
2
+ import logging
3
+ from typing import Optional
4
+
5
+ from opentrons.hardware_control.emulation.abstract_emulator import AbstractEmulator
6
+ from opentrons.hardware_control.emulation.connection_handler import ConnectionHandler
7
+
8
+ log = logging.getLogger(__name__)
9
+
10
+
11
+ async def run_emulator_client(
12
+ host: str,
13
+ port: int,
14
+ emulator: AbstractEmulator,
15
+ retries: int = 3,
16
+ interval_seconds: float = 0.1,
17
+ ) -> None:
18
+ """Run an emulator as a client.
19
+
20
+ Args:
21
+ host: Host to connect to.
22
+ port: Port to connect on.
23
+ emulator: The emulator instance.
24
+ retries: Number of retries on a failed connection attempt.
25
+ interval_seconds: How long to wait between retries.
26
+
27
+ Returns:
28
+ None
29
+ """
30
+ log.info(f"Connecting to {emulator.__class__.__name__} at {host}:{port}")
31
+
32
+ r: Optional[asyncio.StreamReader] = None
33
+ w: Optional[asyncio.StreamWriter] = None
34
+ for i in range(retries):
35
+ try:
36
+ r, w = await asyncio.open_connection(host, port)
37
+ break
38
+ except IOError:
39
+ log.error(
40
+ f"{emulator.__class__.__name__} failed to connect on "
41
+ f"try {i + 1}. Retrying in {interval_seconds} seconds."
42
+ )
43
+ await asyncio.sleep(interval_seconds)
44
+
45
+ if r is None or w is None:
46
+ raise IOError(
47
+ f"Failed to connect to {emulator.__class__.__name__} at "
48
+ f"{host}:{port} after {retries} retries."
49
+ )
50
+
51
+ connection = ConnectionHandler(emulator)
52
+ await connection(r, w)
53
+
54
+
55
+ async def run_emulator_server(host: str, port: int, emulator: AbstractEmulator) -> None:
56
+ """Run an emulator as a server.
57
+
58
+ Args:
59
+ host: Host to listen on.
60
+ port: Port to listen on.
61
+ emulator: Emulator instance.
62
+
63
+ Returns:
64
+ None
65
+ """
66
+ log.info(f"Starting {emulator.__class__.__name__} at {host}:{port}")
67
+ server = await asyncio.start_server(ConnectionHandler(emulator), host, port)
68
+ await server.serve_forever()
@@ -0,0 +1,54 @@
1
+ """Script for starting up emulation up with module emulators."""
2
+ import logging
3
+ import asyncio
4
+ from argparse import ArgumentParser
5
+ from typing import List
6
+
7
+ from opentrons.hardware_control.emulation.app import Application
8
+ from opentrons.hardware_control.emulation.scripts.run_module_emulator import (
9
+ emulator_builder,
10
+ )
11
+ from opentrons.hardware_control.emulation.settings import Settings
12
+ from .run_module_emulator import run as run_module_by_name
13
+
14
+
15
+ async def run(settings: Settings, modules: List[str]) -> None:
16
+ """Run the emulator app with connected module emulators.
17
+
18
+ Args:
19
+ settings: App settings.
20
+ modules: The module emulators to start.
21
+
22
+ Returns:
23
+ None
24
+
25
+ """
26
+ loop = asyncio.get_event_loop()
27
+
28
+ app_task = loop.create_task(Application(settings=settings).run())
29
+ module_tasks = [
30
+ loop.create_task(
31
+ run_module_by_name(settings=settings, emulator_name=n, host="localhost")
32
+ )
33
+ for n in modules
34
+ ]
35
+ await asyncio.gather(app_task, *module_tasks)
36
+
37
+
38
+ def main() -> None:
39
+ """Entry point."""
40
+ a = ArgumentParser()
41
+ a.add_argument(
42
+ "--m",
43
+ action="append",
44
+ choices=emulator_builder.keys(),
45
+ help="which module(s) to emulate.",
46
+ )
47
+ args = a.parse_args()
48
+
49
+ logging.basicConfig(format="%(asctime)s:%(message)s", level=logging.DEBUG)
50
+ asyncio.run(run(Settings(), args.m))
51
+
52
+
53
+ if __name__ == "__main__":
54
+ main()
@@ -0,0 +1,72 @@
1
+ """Script for starting up a python module emulator."""
2
+ import logging
3
+ import asyncio
4
+ from argparse import ArgumentParser
5
+ from typing import Dict, Callable
6
+ from typing_extensions import Final
7
+
8
+ from opentrons.hardware_control.emulation.abstract_emulator import AbstractEmulator
9
+ from opentrons.hardware_control.emulation.heater_shaker import HeaterShakerEmulator
10
+ from opentrons.hardware_control.emulation.types import ModuleType
11
+ from opentrons.hardware_control.emulation.magdeck import MagDeckEmulator
12
+ from opentrons.hardware_control.emulation.parser import Parser
13
+ from opentrons.hardware_control.emulation.tempdeck import TempDeckEmulator
14
+ from opentrons.hardware_control.emulation.thermocycler import ThermocyclerEmulator
15
+
16
+
17
+ from opentrons.hardware_control.emulation.run_emulator import run_emulator_client
18
+ from opentrons.hardware_control.emulation.settings import Settings, ProxySettings
19
+
20
+ emulator_builder: Final[Dict[str, Callable[[Settings], AbstractEmulator]]] = {
21
+ ModuleType.Magnetic.value: lambda s: MagDeckEmulator(Parser(), s.magdeck),
22
+ ModuleType.Temperature.value: lambda s: TempDeckEmulator(Parser(), s.tempdeck),
23
+ ModuleType.Thermocycler.value: lambda s: ThermocyclerEmulator(
24
+ Parser(), s.thermocycler
25
+ ),
26
+ ModuleType.Heatershaker.value: lambda s: HeaterShakerEmulator(
27
+ Parser(), s.heatershaker
28
+ ),
29
+ }
30
+
31
+ emulator_port: Final[Dict[str, Callable[[Settings], ProxySettings]]] = {
32
+ ModuleType.Magnetic.value: lambda s: s.magdeck_proxy,
33
+ ModuleType.Temperature.value: lambda s: s.temperature_proxy,
34
+ ModuleType.Thermocycler.value: lambda s: s.thermocycler_proxy,
35
+ ModuleType.Heatershaker.value: lambda s: s.heatershaker_proxy,
36
+ }
37
+
38
+
39
+ async def run(settings: Settings, emulator_name: str, host: str) -> None:
40
+ """Run an emulator.
41
+
42
+ Args:
43
+ settings: emulator settings
44
+ emulator_name: Name of emulator. This must be a key in emulator_builder
45
+ host: host to connect to.
46
+
47
+ Returns:
48
+ None
49
+ """
50
+ e = emulator_builder[emulator_name](settings)
51
+ proxy_settings = emulator_port[emulator_name](settings)
52
+ await run_emulator_client(host, proxy_settings.emulator_port, e)
53
+
54
+
55
+ def main() -> None:
56
+ """Entry point."""
57
+ a = ArgumentParser()
58
+ a.add_argument(
59
+ "emulator",
60
+ type=str,
61
+ choices=emulator_builder.keys(),
62
+ help="which module to emulate.",
63
+ )
64
+ a.add_argument("host", type=str, help="the emulator host")
65
+ args = a.parse_args()
66
+
67
+ logging.basicConfig(format="%(asctime)s:%(message)s", level=logging.DEBUG)
68
+ asyncio.run(run(Settings(), args.emulator, args.host))
69
+
70
+
71
+ if __name__ == "__main__":
72
+ main()
@@ -0,0 +1,37 @@
1
+ """Script for starting up a python smoothie emulator."""
2
+ import logging
3
+ import asyncio
4
+
5
+ from opentrons.hardware_control.emulation.smoothie import SmoothieEmulator
6
+ from opentrons.hardware_control.emulation.parser import Parser
7
+
8
+
9
+ from opentrons.hardware_control.emulation.run_emulator import run_emulator_server
10
+ from opentrons.hardware_control.emulation.settings import Settings
11
+
12
+
13
+ async def run(settings: Settings) -> None:
14
+ """Run the smoothie emulator.
15
+
16
+ Args:
17
+ settings: emulator settings
18
+
19
+ Returns:
20
+ None
21
+ """
22
+ smoothie = SmoothieEmulator(parser=Parser(), settings=settings.smoothie)
23
+ await run_emulator_server(
24
+ host=settings.smoothie.host,
25
+ port=settings.smoothie.port,
26
+ emulator=smoothie,
27
+ )
28
+
29
+
30
+ def main() -> None:
31
+ """Entry point."""
32
+ logging.basicConfig(format="%(asctime)s:%(message)s", level=logging.DEBUG)
33
+ asyncio.run(run(Settings()))
34
+
35
+
36
+ if __name__ == "__main__":
37
+ main()