Skip to content

Commit

Permalink
Merge branch 'chore_release-7.0.0' into copy-review-aug17
Browse files Browse the repository at this point in the history
  • Loading branch information
ecormany authored Sep 13, 2023
2 parents 2406565 + b4430d9 commit 365a83a
Show file tree
Hide file tree
Showing 611 changed files with 11,677 additions and 8,785 deletions.
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -380,10 +380,10 @@ ssh-keygen # note the path you save the key to
make -C robot-server install-key br_ssh_pubkey=/path/to/pubkey host=${some_other_ip_address}
```

and subsequently, when you do `make term`, add the `br_ssh_key=/path/to/key` option:
and subsequently, when you do `make term`, add the `ssh_key=/path/to/key` option:

```shell
make term br_ssh_key=/path/to/privkey
make term ssh_key=/path/to/privkey
```

If you create the key as `~/.ssh/robot_key` and `~/.ssh/robot_key.pub` then `make term` and `make install-key` will work without arguments.
Expand Down
11 changes: 9 additions & 2 deletions api-client/src/instruments/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
export type InstrumentData = PipetteData | GripperData | BadPipette | BadGripper

// pipettes module already exports type `Mount`
type Mount = 'left' | 'right' | 'extension'

export interface SharedInstrumentData {
mount: Mount
}
export interface GripperData {
data: {
jawState: string
Expand All @@ -11,7 +18,7 @@ export interface GripperData {
firmwareVersion?: string
instrumentModel: string
instrumentType: 'gripper'
mount: string
mount: 'extension'
serialNumber: string
subsystem: 'gripper'
ok: true
Expand All @@ -31,7 +38,7 @@ export interface PipetteData {
instrumentName: string
instrumentModel: string
instrumentType: 'pipette'
mount: string
mount: 'left' | 'right'
serialNumber: string
subsystem: 'pipette_left' | 'pipette_right'
ok: true
Expand Down
18 changes: 18 additions & 0 deletions api-client/src/protocols/getProtocolAnalysisAsDocument.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { GET, request } from '../request'

import type { ResponsePromise } from '../request'
import type { HostConfig } from '../types'
import type { CompletedProtocolAnalysis } from '@opentrons/shared-data'

export function getProtocolAnalysisAsDocument(
config: HostConfig,
protocolId: string,
analysisId: string
): ResponsePromise<CompletedProtocolAnalysis> {
return request<CompletedProtocolAnalysis>(
GET,
`/protocols/${protocolId}/analyses/${analysisId}/asDocument`,
null,
config
)
}
1 change: 1 addition & 0 deletions api-client/src/protocols/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export { getProtocol } from './getProtocol'
export { getProtocolAnalyses } from './getProtocolAnalyses'
export { getProtocolAnalysisAsDocument } from './getProtocolAnalysisAsDocument'
export { deleteProtocol } from './deleteProtocol'
export { createProtocol } from './createProtocol'
export { getProtocols } from './getProtocols'
Expand Down
25 changes: 13 additions & 12 deletions api/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,12 @@ test_opts ?=
pypi_username ?=
pypi_password ?=

# Host key location for buildroot robot
br_ssh_key ?= $(default_ssh_key)
# Other SSH args for buildroot robots
# Host key location for robot
ssh_key ?= $(default_ssh_key)
# Other SSH args for robot
ssh_opts ?= $(default_ssh_opts)
# Helper to safely bundle ssh options
ssh_helper = $(if $(ssh_key),-i $(ssh_key)) $(ssh_opts)

twine_auth_args := --username $(pypi_username) --password $(pypi_password)
twine_repository_url ?= $(pypi_test_upload_url)
Expand Down Expand Up @@ -171,24 +173,23 @@ local-shell:

.PHONY: push-no-restart
push-no-restart: wheel
$(call push-python-package,$(host),$(br_ssh_key),$(ssh_opts),$(wheel_file))
$(call push-python-package,$(host),$(ssh_key),$(ssh_opts),$(wheel_file))

.PHONY: push
push: push-no-restart
$(call restart-service,$(host),$(br_ssh_key),$(ssh_opts),"jupyter-notebook opentrons-robot-server")
$(call restart-service,$(host),$(ssh_key),$(ssh_opts),"jupyter-notebook opentrons-robot-server")

.PHONY: push-no-restart-ot3
push-no-restart-ot3: sdist
echo $(sdist_file)
$(call push-python-sdist,$(host),,$(ssh_opts),$(sdist_file),/opt/opentrons-robot-server,opentrons,src,,$(version_file))
ssh $(ssh_opts) root@$(host) "mount -o remount,rw / && mkdir -p /usr/local/bin"
scp $(ssh_opts) ./src/opentrons/hardware_control/scripts/ot3repl root@$(host):/usr/local/bin/ot3repl
scp $(ssh_opts) ./src/opentrons/hardware_control/scripts/ot3gripper root@$(host):/usr/local/bin/ot3gripper
ssh $(ssh_opts) root@$(host) "mount -o remount,ro /"
$(call push-python-sdist,$(host),$(ssh_key),$(ssh_opts),$(sdist_file),/opt/opentrons-robot-server,opentrons,src,,$(version_file))
ssh $(ssh_helper) root@$(host) "mount -o remount,rw / && mkdir -p /usr/local/bin"
scp $(ssh_helper) ./src/opentrons/hardware_control/scripts/{ot3repl,ot3gripper} root@$(host):/usr/local/bin/
ssh $(ssh_helper) root@$(host) "mount -o remount,ro /"

.PHONY: push-ot3
push-ot3: push-no-restart-ot3
$(call restart-server,$(host),,$(ssh_opts),"opentrons-robot-server")
$(call restart-server,$(host),$(host),$(ssh_opts),"opentrons-robot-server")

.PHONY: simulate
simulate:
Expand All @@ -206,7 +207,7 @@ deploy: wheel
# User must currently specify host, e.g.: `make term host=169.254.202.176`
.PHONY: term
term:
ssh -i $(br_ssh_key) $(ssh_opts) root@$(host)
ssh $(ssh_helper) root@$(host)

.PHONY: plot-session
plot-session:
Expand Down
4 changes: 2 additions & 2 deletions api/mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ warn_untyped_fields = True

# TODO(mc, 2021-09-08): fix and remove any / all of the
# overrides below whenever able
# ~125 errors
[mypy-opentrons.protocols.advanced_control.*,opentrons.protocols.api_support.*,opentrons.protocols.duration.*,opentrons.protocols.execution.*,opentrons.protocols.geometry.*,opentrons.protocols.models.*,opentrons.protocols.labware.*]
# ~115 errors
[mypy-opentrons.protocols.advanced_control.*,opentrons.protocols.api_support.*,opentrons.protocols.duration.*,opentrons.protocols.execution.dev_types,opentrons.protocols.execution.execute_json_v4,opentrons.protocols.execution.execute_python,opentrons.protocols.geometry.*,opentrons.protocols.models.*,opentrons.protocols.labware.*]
disallow_any_generics = False
disallow_untyped_defs = False
disallow_untyped_calls = False
Expand Down
2 changes: 2 additions & 0 deletions api/release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ log][]. For a list of currently known issues, please see the [Opentrons issue tr

Welcome to the v7.0.0 release of the Opentrons robot software! This release adds support for the Opentrons Flex robot, instruments, modules, and labware.

This update may take longer than usual. Allow **approximately 15 minutes** for your robot to restart. This delay will only happen once.

### New Features

- Flex touchscreen
Expand Down
3 changes: 2 additions & 1 deletion api/src/opentrons/calibration_storage/ot2/pipette_offset.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,13 @@ def get_pipette_offset(
**io.read_cal_file(pipette_calibration_filepath)
)
except FileNotFoundError:
log.warning(f"Calibrations for {pipette_id} on {mount} does not exist.")
log.debug(f"Calibrations for {pipette_id} on {mount} does not exist.")
return None
except (json.JSONDecodeError, ValidationError):
log.warning(
f"Malformed calibrations for {pipette_id} on {mount}. Please factory reset your calibrations."
)
# TODO: Delete the bad calibration here maybe?
return None


Expand Down
2 changes: 1 addition & 1 deletion api/src/opentrons/calibration_storage/ot2/tip_length.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def tip_lengths_for_pipette(
pass
return tip_lengths
except FileNotFoundError:
log.warning(f"Tip length calibrations not found for {pipette_id}")
log.debug(f"Tip length calibrations not found for {pipette_id}")
return tip_lengths


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def get_pipette_offset(
**io.read_cal_file(pipette_calibration_filepath)
)
except FileNotFoundError:
log.warning(f"Calibrations for {pipette_id} on {mount} does not exist.")
log.debug(f"Calibrations for {pipette_id} on {mount} does not exist.")
return None
except (json.JSONDecodeError, ValidationError):
log.warning(
Expand Down
7 changes: 5 additions & 2 deletions api/src/opentrons/calibration_storage/ot3/tip_length.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,22 @@ def tip_lengths_for_pipette(
) -> typing.Dict[str, v1.TipLengthModel]:
tip_lengths = {}
try:
# While you technically could drop some data in for tip length calibration on the flex,
# it is not necessary and there is no UI frontend for it, so this code will mostly be
# taking the FileNotFoundError path.
tip_length_filepath = config.get_tip_length_cal_path() / f"{pipette_id}.json"
all_tip_lengths_for_pipette = io.read_cal_file(tip_length_filepath)
for tiprack, data in all_tip_lengths_for_pipette.items():
try:
tip_lengths[tiprack] = v1.TipLengthModel(**data)
except (json.JSONDecodeError, ValidationError):
log.warning(
log.debug(
f"Tip length calibration is malformed for {tiprack} on {pipette_id}"
)
pass
return tip_lengths
except FileNotFoundError:
log.warning(f"Tip length calibrations not found for {pipette_id}")
# this is the overwhelmingly common case
return tip_lengths


Expand Down
23 changes: 21 additions & 2 deletions api/src/opentrons/config/advanced_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ def __init__(
restart_required: bool = False,
show_if: Optional[Tuple[str, bool]] = None,
internal_only: bool = False,
default_true_on_robot_types: Optional[List[RobotTypeEnum]] = None,
):
self.id = _id
#: The id of the setting for programmatic access through
Expand All @@ -70,6 +71,8 @@ def __init__(
#: A list of RobotTypeEnums that are compatible with this feature flag.
self.internal_only = internal_only
#: A flag determining whether this setting is user-facing.
self.default_true_on_robot_types = default_true_on_robot_types or []
#: Robot types for which null/unset means the setting is activated

def __repr__(self) -> str:
return "{}: {}".format(self.__class__, self.id)
Expand Down Expand Up @@ -152,7 +155,7 @@ class Setting(NamedTuple):
old_id="disable-home-on-boot",
title="Disable home on boot",
description="Prevent robot from homing motors on boot",
robot_type=[RobotTypeEnum.OT2],
robot_type=[RobotTypeEnum.OT2, RobotTypeEnum.FLEX],
),
SettingDefinition(
_id="useOldAspirationFunctions",
Expand All @@ -171,6 +174,7 @@ class Setting(NamedTuple):
"pause your robot only after it has completed its "
"current motion.",
robot_type=[RobotTypeEnum.OT2],
default_true_on_robot_types=[RobotTypeEnum.FLEX],
),
SettingDefinition(
_id="disableFastProtocolUpload",
Expand Down Expand Up @@ -253,6 +257,14 @@ class Setting(NamedTuple):
}


def get_setting_definition(setting_id: str) -> Optional[SettingDefinition]:
clean = _clean_id(setting_id)
for setting in settings:
if setting.id == clean:
return setting
return None


def get_adv_setting(setting: str, robot_type: RobotTypeEnum) -> Optional[Setting]:
setting = _clean_id(setting)
s = get_all_adv_settings(robot_type, include_internal=True)
Expand Down Expand Up @@ -749,11 +761,18 @@ def _ensure(data: Mapping[str, Any]) -> SettingsMap:

def get_setting_with_env_overload(setting_name: str, robot_type: RobotTypeEnum) -> bool:
env_name = "OT_API_FF_" + setting_name
defn = get_setting_definition(setting_name)
if env_name in os.environ:
return os.environ[env_name].lower() in {"1", "true", "on"}
else:
s = get_adv_setting(setting_name, robot_type)
return s.value is True if s is not None else False
if s is not None:
return s.value is True
if defn is None:
return False
if robot_type in defn.default_true_on_robot_types:
return True
return False


_SETTINGS_RESTART_REQUIRED = False
Expand Down
4 changes: 3 additions & 1 deletion api/src/opentrons/execute.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
ThreadManagedHardware,
ThreadManager,
)
from opentrons.protocol_engine.types import PostRunHardwareState

from opentrons.protocols import parse
from opentrons.protocols.api_support.deck_type import (
Expand Down Expand Up @@ -572,7 +573,8 @@ def _create_live_context_pe(
create_protocol_engine_in_thread(
hardware_api=hardware_api.wrapped(),
config=_get_protocol_engine_config(),
drop_tips_and_home_after=False,
drop_tips_after_run=False,
post_run_hardware_state=PostRunHardwareState.STAY_ENGAGED_IN_PLACE,
)
)

Expand Down
9 changes: 6 additions & 3 deletions api/src/opentrons/hardware_control/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -490,14 +490,15 @@ async def _chained_calls() -> None:

asyncio.run_coroutine_threadsafe(_chained_calls(), self._loop)

async def halt(self) -> None:
async def halt(self, disengage_before_stopping: bool = False) -> None:
"""Immediately stop motion, cancel execution manager and cancel running tasks.
After this call, the smoothie will be in a bad state until a call to
:py:meth:`stop`.
"""
await self._backend.hard_halt()
await self._execution_manager.cancel()
if disengage_before_stopping:
await self._backend.hard_halt()
await self._backend.halt()

async def stop(self, home_after: bool = True) -> None:
"""
Expand All @@ -508,6 +509,7 @@ async def stop(self, home_after: bool = True) -> None:
robot. After this call, no further recovery is necessary.
"""
await self._backend.halt() # calls smoothie_driver.kill()
await self._execution_manager.cancel()
self._log.info("Recovering from halt")
await self.reset()
await self.cache_instruments()
Expand Down Expand Up @@ -988,6 +990,7 @@ async def dispense(
mount: top_types.Mount,
volume: Optional[float] = None,
rate: float = 1.0,
push_out: Optional[float] = None,
) -> None:
"""
Dispense a volume of liquid in microliters(uL) using this pipette.
Expand Down
9 changes: 9 additions & 0 deletions api/src/opentrons/hardware_control/backends/ot3controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
LIMIT_SWITCH_OVERTRAVEL_DISTANCE,
map_pipette_type_to_sensor_id,
moving_axes_in_move_group,
gripper_jaw_state_from_fw,
)

try:
Expand Down Expand Up @@ -127,6 +128,7 @@
TipStateType,
FailedTipStateCheck,
EstopState,
GripperJawState,
)
from opentrons.hardware_control.errors import (
InvalidPipetteName,
Expand All @@ -152,6 +154,9 @@
set_deck_light,
get_deck_light_state,
)
from opentrons_hardware.hardware_control.gripper_settings import (
get_gripper_jaw_state,
)

from opentrons_hardware.drivers.gpio import OT3GPIO, RemoteOT3GPIO
from opentrons_shared_data.pipette.dev_types import PipetteName
Expand Down Expand Up @@ -732,6 +737,10 @@ async def gripper_home_jaw(self, duty_cycle: float) -> None:
positions = await runner.run(can_messenger=self._messenger)
self._handle_motor_status_response(positions)

async def get_jaw_state(self) -> GripperJawState:
res = await get_gripper_jaw_state(self._messenger)
return gripper_jaw_state_from_fw(res)

@staticmethod
def _lookup_serial_key(pipette_name: FirmwarePipetteName) -> str:
lookup_name = {
Expand Down
Loading

0 comments on commit 365a83a

Please sign in to comment.