Skip to content

Commit

Permalink
Merge branch 'edge' into rel_into_edge
Browse files Browse the repository at this point in the history
Resolve conflicts in app/src/pages/Protocols/hooks/index.ts.
  • Loading branch information
SyntaxColoring committed Oct 3, 2023
2 parents 21aeb59 + 212e69c commit eefa7bc
Show file tree
Hide file tree
Showing 17 changed files with 524 additions and 202 deletions.
38 changes: 38 additions & 0 deletions api/src/opentrons/protocols/advanced_control/transfers.py
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,11 @@ def _plan_transfer(self):
"""
# reform source target lists
sources, dests = self._extend_source_target_lists(self._sources, self._dests)
self._check_valid_volume_parameters(
disposal_volume=self._strategy.disposal_volume,
air_gap=self._strategy.air_gap,
max_volume=self._instr.max_volume,
)
plan_iter = self._expand_for_volume_constraints(
self._volumes,
zip(sources, dests),
Expand Down Expand Up @@ -571,6 +576,13 @@ def _plan_distribute(self):
.. Dispense air gap -> ...*
"""

self._check_valid_volume_parameters(
disposal_volume=self._strategy.disposal_volume,
air_gap=self._strategy.air_gap,
max_volume=self._instr.max_volume,
)

# TODO: decide whether default disposal vol for distribute should be
# pipette min_vol or should we leave it to being 0 by default and
# recommend users to specify a disposal vol when using distribute.
Expand Down Expand Up @@ -633,6 +645,10 @@ def _expand_for_volume_constraints(
"""Split a sequence of proposed transfers if necessary to keep each
transfer under the given max volume.
"""
# A final defense against an infinite loop.
# Raising a proper exception with a helpful message is left to calling code,
# because it has more context about what the user is trying to do.
assert max_volume > 0
for volume, target in zip(volumes, targets):
while volume > max_volume * 2:
yield max_volume, target
Expand Down Expand Up @@ -680,6 +696,12 @@ def _plan_consolidate(self):
*.. Aspirate -> Air gap -> Touch tip ->..
.. Aspirate -> .....*
"""
# TODO: verify if _check_valid_volume_parameters should be re-enabled here
# self._check_valid_volume_parameters(
# disposal_volume=self._strategy.disposal_volume,
# air_gap=self._strategy.air_gap,
# max_volume=self._instr.max_volume,
# )
plan_iter = self._expand_for_volume_constraints(
# todo(mm, 2021-03-09): Is it right to use _instr.max_volume here?
# Why don't we account for tip max volume, disposal volume, or air
Expand Down Expand Up @@ -843,6 +865,22 @@ def _map_volume(i):

return [_map_volume(i) for i in range(total)]

def _check_valid_volume_parameters(
self, disposal_volume: float, air_gap: float, max_volume: float
):
if air_gap >= max_volume:
raise ValueError(
"The air gap must be less than the maximum volume of the pipette"
)
elif disposal_volume >= max_volume:
raise ValueError(
"The disposal volume must be less than the maximum volume of the pipette"
)
elif disposal_volume + air_gap >= max_volume:
raise ValueError(
"The sum of the air gap and disposal volume must be less than the maximum volume of the pipette"
)

def _check_valid_well_list(self, well_list, id, old_well_list):
if self._api_version >= APIVersion(2, 2) and len(well_list) < 1:
raise RuntimeError(
Expand Down
75 changes: 75 additions & 0 deletions api/tests/opentrons/protocols/advanced_control/test_transfers.py
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,81 @@ def test_all_options(_instr_labware):
assert xfer_plan_list == exp1


def test_invalid_air_gap_disposal_sum_distribute(_instr_labware):
_instr_labware["ctx"].home()
lw1 = _instr_labware["lw1"]
lw2 = _instr_labware["lw2"]
# Supply the disposal volume assessment with the instrument followed by a disposal value equal to the max volume

options = tx.TransferOptions(
transfer=tx.Transfer(
disposal_volume=_instr_labware["instr"].max_volume / 2,
air_gap=_instr_labware["instr"].max_volume / 2,
)
)
with pytest.raises(ValueError):
plan = tx.TransferPlan(
700,
lw1.columns()[0][0],
lw2.rows()[0][1:3],
_instr_labware["instr"],
max_volume=_instr_labware["instr"].hw_pipette["max_volume"],
api_version=_instr_labware["ctx"].api_version,
mode="distribute",
options=options,
)
# Exhaust the iterator in case it raises the expected exception lazily.
list(plan)


def test_invalid_air_gap_distribute(_instr_labware):
_instr_labware["ctx"].home()
lw1 = _instr_labware["lw1"]
lw2 = _instr_labware["lw2"]
# Supply the disposal volume assessment with the instrument followed by a disposal value equal to the max volume

options = tx.TransferOptions(
transfer=tx.Transfer(air_gap=_instr_labware["instr"].max_volume)
)
with pytest.raises(ValueError):
plan = tx.TransferPlan(
700,
lw1.columns()[0][0],
lw2.rows()[0][1:3],
_instr_labware["instr"],
max_volume=_instr_labware["instr"].hw_pipette["max_volume"],
api_version=_instr_labware["ctx"].api_version,
mode="distribute",
options=options,
)
# Exhaust the iterator in case it raises the expected exception lazily.
list(plan)


def test_invalid_disposal_volume_distribute(_instr_labware):
_instr_labware["ctx"].home()
lw1 = _instr_labware["lw1"]
lw2 = _instr_labware["lw2"]
# Supply the disposal volume assessment with the instrument followed by a disposal value equal to the max volume

options = tx.TransferOptions(
transfer=tx.Transfer(disposal_volume=_instr_labware["instr"].max_volume)
)
with pytest.raises(ValueError):
plan = tx.TransferPlan(
700,
lw1.columns()[0][0],
lw2.rows()[0][1:3],
_instr_labware["instr"],
max_volume=_instr_labware["instr"].hw_pipette["max_volume"],
api_version=_instr_labware["ctx"].api_version,
mode="distribute",
options=options,
)
# Exhaust the iterator in case it raises the expected exception lazily.
list(plan)


def test_oversized_distribute(_instr_labware):
_instr_labware["ctx"].home()
lw1 = _instr_labware["lw1"]
Expand Down
39 changes: 20 additions & 19 deletions app/src/assets/localization/en/device_details.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@
"about_flex_gripper": "About Flex Gripper",
"about_gripper": "About gripper",
"about_module": "About {{name}}",
"about_pipette": "About pipette",
"about_pipette_name": "About {{name}} Pipette",
"about_pipette": "About pipette",
"add": "Add",
"an_error_occurred_while_updating": "An error occurred while updating your pipette's settings.",
"an_error_occurred_while_updating_module": "An error occurred while updating your {{moduleName}}. Please try again.",
"an_error_occurred_while_updating_please_try_again": "An error occurred while updating your pipette's settings. Please try again.",
"an_error_occurred_while_updating": "An error occurred while updating your pipette's settings.",
"attach_gripper": "Attach gripper",
"attach_pipette": "Attach pipette",
"both_mounts": "Both Mounts",
"bundle_firmware_file_not_found": "Bundled fw file not found for module of type: {{module}}",
"calibrate_gripper": "Calibrate gripper",
"calibrate_now": "Calibrate now",
"calibrate_pipette": "Calibrate pipette",
"calibrate_pipette_offset": "Calibrate pipette offset",
"calibrate_pipette": "Calibrate pipette",
"calibration_needed": "Calibration needed. <calLink>Calibrate now</calLink>",
"canceled": "canceled",
"choose_protocol_to_run": "Choose protocol to Run on {{name}}",
Expand All @@ -40,13 +40,13 @@
"estop_disengaged": "E-stop disengaged, but robot operation still halted.",
"estop_pressed": "E-stop pressed. Robot movement is halted.",
"failed": "failed",
"firmware_update_available": "Firmware update available.",
"firmware_update_available_now": "Firmware update available. <updateLink>Update now</updateLink>",
"firmware_update_available": "Firmware update available.",
"firmware_update_failed": "Failed to update module firmware",
"firmware_update_installation_successful": "Installation successful",
"firmware_update_occurring": "Firmware update in progress...",
"have_not_run": "No recent runs",
"have_not_run_description": "After you run some protocols, they will appear here.",
"have_not_run": "No recent runs",
"heater": "Heater",
"height_ranges": "{{gen}} Height Ranges",
"hot_to_the_touch": "<block>Module is <bold>hot</bold> to the touch</block>",
Expand All @@ -55,34 +55,35 @@
"instruments_and_modules": "Instruments and Modules",
"labware_bottom": "Labware Bottom",
"last_run_time": "last run {{number}}",
"left": "left",
"left_right": "Left+Right Mounts",
"left": "left",
"lights": "Lights",
"link_firmware_update": "View Firmware Update",
"location_conflicts": "Location conflicts",
"magdeck_gen1_height": "Height: {{height}}",
"magdeck_gen2_height": "Height: {{height}} mm",
"max_engage_height": "Max Engage Height",
"missing_both": "missing hardware",
"missing_module": "missing {{num}} module",
"missing_module_plural": "missing {{count}} modules",
"missing_module": "missing {{num}} module",
"missing_pipette": "missing {{num}} pipette",
"missing_pipettes_plural": "missing {{count}} pipettes",
"module_actions_unavailable": "Module actions unavailable while protocol is running",
"module_calibration_required": "Module calibration required.",
"module_calibration_required_no_pipette_attached": "Module calibration required. Attach a pipette before running module calibration.",
"module_calibration_required_update_pipette_FW": "Update pipette firmware before proceeding with required module calibration.",
"module_calibration_required": "Module calibration required.",
"module_controls": "Module Controls",
"module_error": "Module error",
"module_error_contact_support": "Try powering the module off and on again. If the error persists, contact Opentrons Support.",
"module_error": "Module error",
"module_name_error": "{{moduleName}} error",
"module_status_range": "Between {{min}} - {{max}} {{unit}}",
"mount": "{{side}} Mount",
"na_speed": "Target: N/A",
"na_temp": "Target: N/A",
"no_protocol_runs": "No protocol runs yet!",
"no_protocols_found": "No protocols found",
"no_recent_runs": "No recent runs",
"no_recent_runs_description": "After you run some protocols, they will appear here.",
"no_recent_runs": "No recent runs",
"num_units": "{{num}} mm",
"offline_instruments_and_modules": "Robot must be on the network to see connected instruments and modules",
"offline_recent_protocol_runs": "Robot must be on the network to see protocol runs",
Expand All @@ -96,38 +97,38 @@
"overflow_menu_lid_temp": "Set lid temperature",
"overflow_menu_mod_temp": "Set module temperature",
"overflow_menu_set_block_temp": "Set block temperature",
"pipette_calibrations_differ": "The attached pipettes have very different calibration values. When properly calibrated, the values should be similar.",
"pipette_cal_recommended": "Pipette Offset calibration recommended.",
"pipette_calibrations_differ": "The attached pipettes have very different calibration values. When properly calibrated, the values should be similar.",
"pipette_offset_calibration_needed": "Pipette Offset calibration needed.",
"pipette_recalibration_recommended": "Pipette recalibration recommended",
"pipette_settings": "{{pipetteName}} Settings",
"plunger_positions": "Plunger Positions",
"power_force": "Power / Force",
"protocol": "Protocol",
"ready": "Ready",
"ready_to_run": "ready to run",
"ready": "Ready",
"recalibrate_gripper": "Recalibrate gripper",
"recalibrate_now": "Recalibrate now",
"recalibrate_pipette": "Recalibrate pipette",
"recalibrate_pipette_offset": "Recalibrate pipette offset",
"recalibrate_pipette": "Recalibrate pipette",
"recent_protocol_runs": "Recent Protocol Runs",
"rerun_now": "Rerun protocol now",
"reset_all": "Reset all",
"reset_estop": "Reset E-stop",
"resume_operation": "Resume operation",
"right": "right",
"robot_control_not_available": "Some robot controls are not available when run is in progress",
"run": "Run",
"robot_initializing": "Initializing...",
"run_a_protocol": "Run a protocol",
"run_again": "Run again",
"run_duration": "Run duration",
"run": "Run",
"serial_number": "Serial Number",
"robot_initializing": "Initializing...",
"set_block_temp": "Set temperature",
"set_block_temperature": "Set block temperature",
"set_engage_height": "Set Engage Height",
"set_engage_height_and_enter_integer": "Set the engage height for this Magnetic Module. Enter an integer between {{lower}} and {{higher}}.",
"set_engage_height_for_module": "Set Engage Height for {{name}}",
"set_engage_height": "Set Engage Height",
"set_lid_temperature": "Set lid temperature",
"set_shake_of_hs": "Set rpm for this module.",
"set_shake_speed": "Set shake speed",
Expand All @@ -142,8 +143,8 @@
"target_temp": "Target: {{temp}} °C",
"tc_block": "Block",
"tc_lid": "Lid",
"tc_set_temperature": "Set {{part}} Temperature for {{name}}",
"tc_set_temperature_body": "Pre heat or cool your Thermocycler {{part}}. Enter a whole number between {{min}} °C and {{max}} °C.",
"tc_set_temperature": "Set {{part}} Temperature for {{name}}",
"tempdeck_slideout_body": "Pre heat or cool your {{model}}. Enter a whole number between 4 °C and 96 °C.",
"tempdeck_slideout_title": "Set Temperature for {{name}}",
"temperature": "Temperature",
Expand All @@ -153,12 +154,12 @@
"to_run_protocol_go_to_protocols_page": "To run a protocol on this robot, import a protocol on the <navlink>Protocols page</navlink>",
"update_now": "Update now",
"updating_firmware": "Updating firmware...",
"usb_port": "usb-{{port}}",
"usb_port_not_connected": "usb not connected",
"usb_port": "usb-{{port}}",
"version": "Version {{version}}",
"view": "View",
"view_pipette_setting": "Pipette Settings",
"view_run_record": "View protocol run record",
"view": "View",
"welcome_modal_description": "A place to run protocols, manage your instruments, and view robot status.",
"welcome_to_your_dashboard": "Welcome to your dashboard!",
"yes_update_now": "Yes, update now"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { useTrackEvent } from '../../../redux/analytics'
import { Skeleton } from '../../../atoms/Skeleton'
import { useMissingProtocolHardware } from '../../../pages/Protocols/hooks'
import { useCloneRun } from '../../ProtocolUpload/hooks'
import { useMissingHardwareText } from './hooks'
import { useHardwareStatusText } from './hooks'
import {
RUN_STATUS_FAILED,
RUN_STATUS_STOPPED,
Expand Down Expand Up @@ -68,10 +68,14 @@ export function ProtocolWithLastRun({
const {
missingProtocolHardware,
isLoading: isLookingForHardware,
conflictedSlots,
} = useMissingProtocolHardware(protocolData.id)
const history = useHistory()
const isReadyToBeReRun = missingProtocolHardware.length === 0
const chipText = useMissingHardwareText(missingProtocolHardware)
const chipText = useHardwareStatusText(
missingProtocolHardware,
conflictedSlots
)
const trackEvent = useTrackEvent()
// TODO(BC, 08/29/23): reintroduce this analytics event when we refactor the hook to fetch data lazily (performance concern)
// const { trackProtocolRunEvent } = useTrackProtocolRunEvent(runData.id)
Expand Down
Loading

0 comments on commit eefa7bc

Please sign in to comment.