Skip to content

Commit

Permalink
feat(app,api): clear module calibration (#13548)
Browse files Browse the repository at this point in the history
Implements clearing module calibration on the flex and ties it into 
device reset, while removing the per-module info deletion that remains
unimplemented.

The module calibration overflow menu allowed you to delete a single
module's calibration data. This was (a) unimplemented (b) a bit of an
uphill battle to implement and (c) unlike all the other calibration
options in the calibration overview page, which just have the ability to
rerun calibration from that overflow. So remove the ability to delete
calibration data here.

Add clearing module calibration to the desktop and on-device display
device reset.

Closes RQA-1526
Closes RQA-1555
Closes RQA-1582
  • Loading branch information
sfoster1 authored Sep 14, 2023
1 parent 9bcbecb commit 002c1e6
Show file tree
Hide file tree
Showing 13 changed files with 56 additions and 147 deletions.
19 changes: 19 additions & 0 deletions api/src/opentrons/config/reset.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class ResetOptionId(str, Enum):
tip_length_calibrations = "tipLengthCalibrations"
runs_history = "runsHistory"
on_device_display = "onDeviceDisplay"
module_calibration = "moduleCalibration"


_OT_2_RESET_OPTIONS = [
Expand All @@ -53,6 +54,7 @@ class ResetOptionId(str, Enum):
ResetOptionId.gripper_offset,
ResetOptionId.runs_history,
ResetOptionId.on_device_display,
ResetOptionId.module_calibration,
]

_settings_reset_options = {
Expand Down Expand Up @@ -87,6 +89,9 @@ class ResetOptionId(str, Enum):
name="On-Device Display Configuration",
description="Clear the configuration of the on-device display (touchscreen)",
),
ResetOptionId.module_calibration: CommonResetOption(
name="Module Calibrations", description="Clear module offset calibrations"
),
}


Expand Down Expand Up @@ -124,6 +129,9 @@ def reset(options: Set[ResetOptionId]) -> None:
if ResetOptionId.gripper_offset in options:
reset_gripper_offset()

if ResetOptionId.module_calibration in options:
reset_module_calibration()


def reset_boot_scripts() -> None:
if IS_ROBOT:
Expand Down Expand Up @@ -151,3 +159,14 @@ def reset_gripper_offset() -> None:
def reset_tip_length_calibrations() -> None:
clear_tip_length_calibration()
clear_pipette_offset_calibrations()


def reset_module_calibration() -> None:
try:
from opentrons.calibration_storage.ot3.module_offset import (
clear_module_offset_calibrations,
)

clear_module_offset_calibrations()
except ImportError:
log.warning("Tried to clear module offset calibrations on an OT-2")
10 changes: 10 additions & 0 deletions api/tests/opentrons/config/test_reset.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ def mock_cal_robot_attitude(
yield m


@pytest.fixture
def mock_cal_module_offset(
robot_model: "RobotModel",
) -> Generator[MagicMock, None, None]:
with patch("opentrons.config.reset.reset_module_calibration") as m:
yield m


def test_get_options() -> None:
options = reset.reset_options("OT-2 Standard")
assert list(options.keys()) == reset._OT_2_RESET_OPTIONS
Expand All @@ -75,12 +83,14 @@ def test_reset_empty_set(
mock_reset_pipette_offset: MagicMock,
mock_reset_deck_calibration: MagicMock,
mock_reset_tip_length_calibrations: MagicMock,
mock_cal_module_offset: MagicMock,
) -> None:
reset.reset(set())
mock_reset_boot_scripts.assert_not_called()
mock_reset_pipette_offset.assert_not_called()
mock_reset_deck_calibration.assert_not_called()
mock_reset_tip_length_calibrations.assert_not_called()
mock_cal_module_offset.assert_not_called()


def test_reset_all_set(
Expand Down
7 changes: 3 additions & 4 deletions app/src/assets/localization/en/device_settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,14 @@
"clear_option_deck_calibration": "Clear deck calibration",
"clear_option_gripper_calibration": "Clear gripper calibration",
"clear_option_gripper_offset_calibrations": "Clear gripper calibration",
"clear_option_module_calibrations": "Clear module calibrations",
"clear_option_module_calibration": "Clear module calibration",
"clear_option_pipette_calibrations": "Clear pipette calibration",
"clear_option_pipette_offset_calibrations": "Clear pipette offset calibrations",
"clear_option_runs_history": "Clear protocol run history",
"clear_option_runs_history_subtext": "Clears information about past runs of all protocols.",
"clear_option_tip_length_calibrations": "Clear tip length calibrations",
"confirm_device_reset_description": "Are you sure you want to reset your device?",
"confirm_device_reset_description": "This will permanently delete all protocol, calibration, and other data. You’ll have to redo initial setup before using the robot again.",
"confirm_device_reset_heading": "Are you sure you want to reset your device?",
"connect": "Connect",
"connect_the_estop_to_continue": "Connect the E-stop to continue",
"connect_to_wifi_network": "Connect to Wi-Fi network",
Expand Down Expand Up @@ -155,8 +156,6 @@
"model_and_serial": "Pipette Model and Serial",
"module": "Module",
"module_calibration": "Module Calibration",
"module_calibration_confirm_modal_body": "This will immediately delete calibration data for this module on this robot.",
"module_calibration_confirm_modal_title": "Are you sure you want to clear module calibration data?",
"module_calibration_description": "Module calibration uses a pipette and attached probe to determine the module's exact position relative to the deck.",
"mount": "Mount",
"name_love_it": "{{name}}, love it!",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,8 @@ export function DeviceResetSlideout({
? options.filter(
opt =>
opt.id === 'pipetteOffsetCalibrations' ||
opt.id === 'gripperOffsetCalibrations'
// ||
// opt.id === 'moduleCalibrations'
opt.id === 'gripperOffsetCalibrations' ||
opt.id === 'moduleCalibration'
)
: []

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ const mockResetConfigOptions = [
name: 'tip length FooBar',
description: 'tip length fooBar description',
},
{
id: 'moduleCalibration',
name: 'module calibration FooBar',
description: 'moduleCalibration fooBar description',
},
]

const render = () => {
Expand Down Expand Up @@ -116,6 +121,7 @@ describe('RobotSettings DeviceResetSlideout', () => {
getByText('Clear gripper calibration')
getByRole('checkbox', { name: 'Clear pipette calibration' })
getByRole('checkbox', { name: 'Clear gripper calibration' })
getByRole('checkbox', { name: 'Clear module calibration' })
expect(
queryByRole('checkbox', { name: 'Clear deck calibration' })
).toBeNull()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import {
THERMOCYCLER_MODULE_TYPE,
} from '@opentrons/shared-data'

import { Divider } from '../../../atoms/structure'
import { OverflowBtn } from '../../../atoms/MenuList/OverflowBtn'
import { MenuItem } from '../../../atoms/MenuList/MenuItem'
import { useMenuHandleClickOutside } from '../../../atoms/MenuList/hooks'
Expand Down Expand Up @@ -117,11 +116,6 @@ export function ModuleCalibrationOverflowMenu({
setShowModuleWizard(true)
}

const handleDeleteCalibration = (): void => {
// ToDo (kk:08/23/2023)
// call a custom hook to delete calibration data
}

React.useEffect(() => {
if (isRunning) {
updateRobotStatus(true)
Expand Down Expand Up @@ -162,14 +156,6 @@ export function ModuleCalibrationOverflowMenu({
>
{isCalibrated ? t('recalibrate_module') : t('calibrate_module')}
</MenuItem>
{isCalibrated ? (
<>
<Divider />
<MenuItem onClick={handleDeleteCalibration} disabled={false}>
{t('clear_calibration_data')}
</MenuItem>
</>
) : null}
</Flex>
) : null}
{menuOverlay}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,18 +94,16 @@ describe('ModuleCalibrationOverflowMenu', () => {
})

it('should render overflow menu buttons - not calibrated', () => {
const [{ getByText, queryByText, getByLabelText }] = render(props)
const [{ getByText, getByLabelText }] = render(props)
getByLabelText('ModuleCalibrationOverflowMenu').click()
getByText('Calibrate module')
expect(queryByText('Clear calibration data')).not.toBeInTheDocument()
})

it('should render overflow menu buttons - calibrated', () => {
props = { ...props, isCalibrated: true }
const [{ getByText, getByLabelText }] = render(props)
getByLabelText('ModuleCalibrationOverflowMenu').click()
getByText('Recalibrate module')
getByText('Clear calibration data')
})

it('should call a mock function when clicking calibrate button', () => {
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

8 changes: 4 additions & 4 deletions app/src/organisms/RobotSettingsDashboard/DeviceReset.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export function DeviceReset({
const targetOptionsOrder = [
'pipetteOffsetCalibrations',
'gripperOffsetCalibrations',
// 'moduleCalibrations',
'moduleCalibration',
'runsHistory',
]
const availableOptions = options
Expand Down Expand Up @@ -116,9 +116,9 @@ export function DeviceReset({
case 'gripperOffsetCalibrations':
optionText = t('clear_option_gripper_calibration')
break
// case 'moduleCalibrations':
// optionText = t('clear_option_module_calibrations')
// break
case 'moduleCalibration':
optionText = t('clear_option_module_calibration')
break
case 'runsHistory':
optionText = t('clear_option_runs_history')
subText = t('clear_option_runs_history_subtext')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ const mockResetConfigOptions = [
name: 'Boot Scripts FooBar',
description: 'bootScripts fooBar description',
},
{
id: 'moduleCalibration',
name: 'Module Calibration FooBar',
description: 'moduleCalibration fooBar description',
},
]

const mockGetResetConfigOptions = getResetConfigOptions as jest.MockedFunction<
Expand Down Expand Up @@ -74,6 +79,7 @@ describe('DeviceReset', () => {
const [{ getByText, getByTestId }] = render(props)
getByText('Clear pipette calibration')
getByText('Clear gripper calibration')
getByText('Clear module calibration')
getByText('Clear protocol run history')
getByText('Clears information about past runs of all protocols.')
expect(getByTestId('DeviceReset_clear_data_button')).toBeDisabled()
Expand All @@ -88,11 +94,13 @@ describe('DeviceReset', () => {
it('when tapping a option button and tapping the clear button, a mock function is called', () => {
const clearMockResetOptions = {
pipetteOffsetCalibrations: true,
moduleCalibration: true,
runsHistory: true,
}
const [{ getByText }] = render(props)
fireEvent.click(getByText('Clear pipette calibration'))
fireEvent.click(getByText('Clear protocol run history'))
fireEvent.click(getByText('Clear module calibration'))
const clearButton = getByText('Clear data and restart robot')
fireEvent.click(clearButton)
getByText('Are you sure you want to reset your device?')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ stages:
- id: onDeviceDisplay
name: On-Device Display Configuration
description: !re_search 'on-device display'
- id: moduleCalibration
name: Module Calibrations
description: !re_search 'Clear module offset calibrations'

- name: POST Reset gripperOffsetCalibrations true on OT-3
request:
Expand Down

0 comments on commit 002c1e6

Please sign in to comment.