Skip to content

Commit 900f080

Browse files
committed
Merge back 'chore_release-8.5.0' into 'chore_release-pd-8.5.0'
Manually resolved conflicts: - app-shell/electron-builder.config.js - components/src/organisms/CommandText/__tests__/CommandText.test.tsx - protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/MoveLiquidTools/__tests__/LiquidClassesStepTools.test.tsx - react-api-client/src/system/useAuthorization.ts
2 parents 04554a5 + f055f04 commit 900f080

File tree

41 files changed

+758
-206
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+758
-206
lines changed

.github/workflows/app-test-build-deploy.yaml

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ concurrency:
4343
cancel-in-progress: true
4444

4545
env:
46-
CI: "true"
46+
CI: 'true'
4747
_APP_DEPLOY_BUCKET_ROBOTSTACK: builds.opentrons.com
4848
_APP_DEPLOY_FOLDER_ROBOTSTACK: app
4949
_APP_DEPLOY_BUCKET_OT3: ot3-development.builds.opentrons.com
@@ -211,6 +211,32 @@ jobs:
211211
python-version: '3.10'
212212
- name: check make version
213213
run: make --version
214+
- name: 'Configure Windows code signing environment'
215+
if: startsWith(matrix.os, 'windows') && contains(needs.determine-build-type.outputs.type, 'release')
216+
shell: bash
217+
run: |
218+
echo "${{ secrets.SM_CLIENT_CERT_FILE_B64_V2 }}" | base64 --decode > /d/Certificate_pkcs12.p12
219+
echo "${{ secrets.WINDOWS_CSC_B64_V2 }}" | base64 --decode > /d/opentrons_labworks_inc.crt
220+
echo "C:\Program Files (x86)\Windows Kits\10\App Certification Kit" >> $GITHUB_PATH
221+
echo "C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools" >> $GITHUB_PATH
222+
echo "C:\Program Files\DigiCert\DigiCert Keylocker Tools" >> $GITHUB_PATH
223+
224+
- name: 'Setup Windows code signing helpers'
225+
if: startsWith(matrix.os, 'windows') && contains(needs.determine-build-type.outputs.type, 'release')
226+
shell: cmd
227+
env:
228+
SM_HOST: ${{ secrets.SM_HOST_V2 }}
229+
SM_CLIENT_CERT_FILE: "D:\\Certificate_pkcs12.p12"
230+
SM_CLIENT_CERT_PASSWORD: ${{secrets.SM_CLIENT_CERT_PASSWORD_V2}}
231+
SM_API_KEY: ${{secrets.SM_API_KEY_V2}}
232+
run: |
233+
curl -X GET https://one.digicert.com/signingmanager/api-ui/v1/releases/Keylockertools-windows-x64.msi/download -H "x-api-key:${{secrets.SM_API_KEY_V2}}" -o Keylockertools-windows-x64.msi
234+
msiexec /i Keylockertools-windows-x64.msi /quiet /qn
235+
smksp_registrar.exe list
236+
smctl.exe keypair ls
237+
C:\Windows\System32\certutil.exe -csp "DigiCert Signing Manager KSP" -key -user
238+
smksp_cert_sync.exe
239+
smctl.exe healthcheck --all
214240
215241
# Do the frontend dist bundle
216242
- name: 'bundle ${{matrix.variant}} frontend'
@@ -221,32 +247,6 @@ jobs:
221247
run: |
222248
make -C app dist
223249
224-
- name: Install and Invoke TrustedSigning @0.5.3 on dummy executable
225-
# Work around from https://github.com/electron-userland/electron-builder/issues/9076#issuecomment-2855541018
226-
if: startsWith(matrix.os, 'windows') && contains(needs.determine-build-type.outputs.type, 'release')
227-
shell: pwsh
228-
run: |
229-
Install-Module -Name TrustedSigning -RequiredVersion 0.5.3 -Force -Repository PSGallery
230-
# Create a dummy executable file
231-
$dummyExePath = Join-Path -Path $env:GITHUB_WORKSPACE -ChildPath "dummy.exe"
232-
Set-Content -Path $dummyExePath -Value "This is a dummy executable for testing purposes."
233-
# Invoke Trusted Signing on the dummy executable
234-
# Necessary to force dependency resolution
235-
try {
236-
Invoke-TrustedSigning `
237-
-Endpoint 'https://eus.codesigning.azure.net/' `
238-
-CertificateProfileName 'dummyName' `
239-
-CodeSigningAccountName 'dummyName' `
240-
-TimestampRfc3161 'http://timestamp.acs.microsoft.com' `
241-
-TimestampDigest 'SHA256' `
242-
-FileDigest 'SHA256' `
243-
-Files $dummyExePath
244-
} catch {
245-
Write-Host "Invoke-TrustedSigning failed: $($_.Exception.Message)"
246-
# Prevent the script from exiting with a non-zero status
247-
exit 0
248-
}
249-
250250
# build the desktop app and deploy it
251251
- name: 'build ${{matrix.variant}} app for ${{ matrix.os }}'
252252
if: matrix.target == 'desktop'
@@ -255,9 +255,13 @@ jobs:
255255
OT_APP_MIXPANEL_ID: ${{ secrets.OT_APP_MIXPANEL_ID }}
256256
OT_APP_INTERCOM_ID: ${{ secrets.OT_APP_INTERCOM_ID }}
257257
WINDOWS_SIGN: ${{ format('{0}', contains(needs.determine-build-type.outputs.type, 'release')) }}
258-
AZURE_TENANT_ID: ${{secrets.AZURE_TENANT_ID}}
259-
AZURE_CLIENT_ID: ${{secrets.AZURE_CLIENT_ID}}
260-
AZURE_CLIENT_SECRET: ${{secrets.AZURE_CLIENT_SECRET}}
258+
SM_CODE_SIGNING_CERT_SHA1_HASH: ${{secrets.SM_CODE_SIGNING_CERT_SHA1_HASH_V3}}
259+
SM_KEYPAIR_ALIAS: ${{secrets.SM_KEYPAIR_ALIAS_V3}}
260+
SM_HOST: ${{ secrets.SM_HOST_V2 }}
261+
SM_CLIENT_CERT_FILE: "D:\\Certificate_pkcs12.p12"
262+
SM_CLIENT_CERT_PASSWORD: ${{secrets.SM_CLIENT_CERT_PASSWORD_V2}}
263+
SM_API_KEY: ${{secrets.SM_API_KEY_V2}}
264+
WINDOWS_CSC_FILEPATH: "D:\\opentrons_labworks_inc.crt"
261265
CSC_LINK: ${{ secrets.OT_APP_CSC_MACOS_V2 }}
262266
CSC_KEY_PASSWORD: ${{ secrets.OT_APP_CSC_KEY_MACOS_V2 }}
263267
APPLE_ID: ${{ secrets.OT_APP_APPLE_ID_V2 }}

api/docs/templates/v2/remote-nav.html

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,10 @@
6767
.wp-block-pullquote{font-size: 1.5em;line-height: 1.6;}
6868
</style>
6969
<link rel='stylesheet' id='auth0-widget-css' href='https://opentrons.com/wp-content/plugins/auth0/assets/css/main.css?ver=4.6.2' type='text/css' media='all' />
70-
<link rel='stylesheet' id='bigcommerce-styles-css' href='https://opentrons.com/wp-content/plugins/bigcommerce/assets/css/master.min.css?ver=5.0.8-11.48.12.14.2023' type='text/css' media='all' />
71-
<link rel='stylesheet' id='style-css' href='https://opentrons.com/wp-content/themes/timberland/theme/assets/build/app.css?id=06ae55a365bd3e1b84ee097bbfe9cb49&#038;ver=6.5.5' type='text/css' media='all' />
72-
<link rel='stylesheet' id='algolia-autocomplete-css' href='https://opentrons.com/wp-content/plugins/wp-search-with-algolia/css/algolia-autocomplete.css?ver=2.8.1' type='text/css' media='all' />
70+
<link rel='stylesheet' id='bigcommerce-styles-css' href='https://opentrons.com/wp-content/plugins/bigcommerce/assets/css/master.min.css?ver=5.1.2-4.39.09.12.2024' type='text/css' media='all' />
71+
<link rel='stylesheet' id='timberland-app-css' href='https://opentrons.com/wp-content/themes/timberland/theme/assets/build/css/app.css?id=e3cd5368a82afb21e5316b601787a0e5' type='text/css' media='all' />
72+
<link rel='stylesheet' id='youtube-popup-style-css' href='https://opentrons.com/wp-content/themes/timberland/theme/assets/styles/YouTubePopUp.css?ver=6.7.1' type='text/css' media='all' />
73+
<link rel='stylesheet' id='algolia-autocomplete-css' href='https://opentrons.com/wp-content/plugins/wp-search-with-algolia/css/algolia-autocomplete.css?ver=2.8.2' type='text/css' media='all' />
7374
<script type="text/javascript" src="https://opentrons.com/wp-includes/js/jquery/jquery.min.js?ver=3.7.1" id="jquery-core-js"></script>
7475
<script type="text/javascript" src="https://opentrons.com/wp-includes/js/jquery/jquery-migrate.min.js?ver=3.4.1" id="jquery-migrate-js"></script>
7576
<link rel="https://api.w.org/" href="https://opentrons.com/wp-json/" /><link rel="alternate" type="application/json" href="https://opentrons.com/wp-json/wp/v2/pages/1927" /><link rel="EditURI" type="application/rsd+xml" title="RSD" href="https://opentrons.com/xmlrpc.php?rsd" />

api/docs/v2/basic_commands/liquids.rst

Lines changed: 75 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,17 @@ Flex and OT-2 pipettes aspirate at :ref:`default flow rates <new-plunger-flow-ra
8686

8787
.. versionadded:: 2.0
8888

89+
90+
You can also specify an absolute ``flow_rate`` to set the flow rate in µL/second::
91+
92+
pipette.aspirate(200, plate["A1"], flow_rate=50)
93+
94+
.. versionchanged:: 2.24
95+
Add the aspirate ``flow_rate`` parameter.
96+
97+
The ``rate`` and ``flow_rate`` parameters are mutually exclusive. If you specify both in the same command, the API will raise an error.
98+
99+
89100
.. _new-dispense:
90101

91102
Dispense
@@ -163,6 +174,18 @@ Flex and OT-2 pipettes dispense at :ref:`default flow rates <new-plunger-flow-ra
163174

164175
.. versionadded:: 2.0
165176

177+
You can also specify an absolute ``flow_rate`` to set the flow rate in µL/second::
178+
179+
pipette.dispense(200, plate["B1"], flow_rate=50)
180+
181+
.. versionchanged:: 2.24
182+
Add the dispense ``flow_rate`` parameter.
183+
184+
The ``rate`` and ``flow_rate`` parameters are mutually exclusive. If you specify both in the same command, the API will raise an error.
185+
186+
187+
188+
166189
.. _push-out-dispense:
167190

168191
Push Out After Dispense
@@ -245,21 +268,30 @@ These optional location arguments give you control over where the tip will touch
245268
This example demonstrates touching the tip in a specific well::
246269

247270
pipette.touch_tip(plate["B1"])
271+
272+
.. versionadded:: 2.0
248273

249274
This example uses an offset to set the touch tip location 2mm below the top of the current well::
250275

251276
pipette.touch_tip(v_offset=-2)
252277

253278
This example moves the pipette 75% of well's total radius and 2 mm below the top of well::
254279

255-
pipette.touch_tip(plate["B1"],
256-
radius=0.75,
257-
v_offset=-2)
280+
pipette.touch_tip(plate["B1"], radius=0.75, v_offset=-2)
281+
282+
And this example uses ``mm_from edge`` to set the touch tip location 0 mm, or the edge of the current well::
283+
284+
pipette.touch_tip(plate["B1"], mm_from_edge=0)
285+
286+
.. versionchanged:: 2.24
287+
Add the ``mm_from_edge`` parameter.
258288

259-
The ``touch_tip`` feature allows the pipette to touch the edges of a well gently instead of crashing into them. It includes the ``radius`` argument. When ``radius=1`` the robot moves the centerline of the pipette’s plunger axis to the edge of a well. This means a pipette tip may sometimes touch the well wall too early, causing it to bend inwards. A smaller radius helps avoid premature wall collisions and a lower speed produces gentler motion. Different liquid droplets behave differently, so test out these parameters in a single well before performing a full protocol run.
289+
The ``touch_tip`` feature allows the pipette to touch the edges of a well gently instead of crashing into them. It includes the ``radius`` and ``mm_from_edge`` arguments. When ``radius=1`` or ``mm_from_edge=0``,the robot moves the centerline of the pipette’s plunger axis to the edge of a well. This means a pipette tip may sometimes touch the well wall too early, causing it to bend inwards. A smaller radius or larger ``mm_from_edge``, like 1 mm, help avoid premature wall collisions and a lower speed produces gentler motion. Different liquid droplets behave differently, so test out these parameters in a single well before performing a full protocol run.
290+
291+
The ``radius`` and ``mm_from_edge`` arguments are mutually exclusive. If you specify both in the same command, the API will raise an error.
260292

261293
.. warning::
262-
*Do not* set the ``radius`` value greater than ``1.0``. When ``radius`` is > ``1.0``, the robot will forcibly move the pipette tip across a well wall or edge. This type of aggressive movement can damage the pipette tip and the pipette.
294+
*Do not* set the ``radius`` value greater than ``1.0`` or a negative ``mm_from_edge`` value. When ``radius`` is > ``1.0`` or ``mm_from_edge`` is < ``0.0``, the robot will forcibly move the pipette tip across a well wall or edge. This type of aggressive movement can damage the pipette tip and the pipette.
263295

264296
Touch Speed
265297
-----------
@@ -276,11 +308,11 @@ This example uses the current well and sets the speed to 80 mm/s::
276308

277309
pipette.touch_tip(speed=80)
278310

279-
.. versionadded:: 2.0
280-
281311
.. versionchanged:: 2.4
282312
Lowered minimum speed to 1 mm/s.
283313

314+
315+
284316
.. _mix:
285317

286318
Mix
@@ -300,18 +332,35 @@ This example draws an amount equal to the pipette's maximum rated volume and mix
300332

301333
pipette.mix(repetitions=3)
302334

335+
Like an ``aspirate()`` or ``dispense()``, you can use optional arguments to specify the flow rate, a delay, or a push out after an aspirate or dispense in the mix.
336+
337+
This example draws 100 µL from the current well and mixes it three times, aspirating at 50 µL/sec and with a 5 second delay after each aspirate::
338+
339+
pipette.mix(
340+
repetitions=3,
341+
volume=100,
342+
aspirate_flow_rate=50,
343+
aspirate_delay=5
344+
)
345+
346+
And this example adds a push out of 10 µL after the final dispense in the mix::
347+
348+
pipette.mix(repetitions=3, volume=100, final_push_out=10)
349+
303350
.. note::
304351

305352
In API versions 2.2 and earlier, during a mix, the pipette moves up and out of the target well. In API versions 2.3 and later, the pipette does not move while mixing.
306353

307354
.. versionadded:: 2.0
355+
.. versionchanged:: 2.24
356+
Adds the ``aspirate_flow_rate``, ``dispense_flow_rate``, ``aspirate_delay``, ``dispense_delay``, and ``final_push_out`` parameters.
308357

309358
.. _air-gap:
310359

311360
Air Gap
312361
=======
313362

314-
The :py:meth:`.InstrumentContext.air_gap` method tells the pipette to draw in air before or after a liquid. Creating an air gap helps keep liquids from seeping out of a pipette after drawing it from a well. This method includes arguments that give you control over the amount of air to aspirate and the pipette's height (in mm) above the well. By default, the pipette moves 5 mm above a well before aspirating air. Calling :py:meth:`~.InstrumentContext.air_gap` with no arguments uses the entire remaining volume in the pipette.
363+
The :py:meth:`.InstrumentContext.air_gap` method tells the pipette to draw in air before or after a liquid. Creating an air gap helps keep liquids from seeping out of a pipette after drawing it from a well. This method includes arguments that give you control over the amount of air to aspirate and the position at the target well to add the air gap. By default, the pipette moves 5 mm above the center of a well before aspirating air. Calling :py:meth:`~.InstrumentContext.air_gap` with no arguments uses the entire remaining volume in the pipette.
315364

316365
This example aspirates 200 µL of air 5 mm above the current well::
317366

@@ -325,7 +374,25 @@ This example aspirates enough air to fill the remaining volume in a pipette::
325374

326375
pipette.air_gap()
327376

377+
Instead of moving to a distance above the target well, this example uses the ``in_place`` parameter to immediately add add an air gap after an aspirate or dispense. Here, the pipette aspirates 200 µL of air while still inside the target well::
378+
379+
pipette.air_gap(volume=200, in_place=True)
380+
381+
Just like in an ``aspirate()`` or ``dispense()``, you can use the ``rate`` and ``flow_rate`` parameters to change the flow rate.
382+
383+
This example uses the ``rate`` parameter to aspirate 200 µL of air at twice the default flow rate::
384+
385+
pipette.air_gap(volume=200, rate=2.0)
386+
387+
This example uses the ``flow_rate`` parameter to aspirate 200 µL of air at 50 µL/sec::
388+
389+
pipette.air_gap(volume=200, flow_rate=50)
390+
391+
The ``rate`` and ``flow_rate`` parameters are mutually exclusive. If you choose to change the ``flow_rate``, specifying a ``rate`` will raise an error.
392+
328393
.. versionadded:: 2.0
394+
.. versionchanged:: 2.24
395+
Add the ``in_place`` and ``flow_rate`` parameters.
329396

330397
.. _detect-liquid-presence:
331398

api/docs/v2/parameters/defining.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ The examples on this page assume the following definition, which uses the argume
6262

6363
.. code-block::
6464
65-
def add_parameters(parameters: protocol_api.Parameters):
65+
def add_parameters(parameters: protocol_api.ParameterContext):
6666
6767
Within this function definition, call methods on ``parameters`` to define parameters. The next section demonstrates how each type of parameter has its own method.
6868

api/src/opentrons/protocol_api/core/engine/instrument.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1698,15 +1698,15 @@ def _pick_up_tip() -> Tuple[Location, WellCore]:
16981698
conditioning_volume=conditioning_vol,
16991699
)
17001700

1701-
# If the tip has volumes correspoinding to multiple destinations, then
1701+
# If the tip has volumes corresponding to multiple destinations, then
17021702
# multi-dispense in those destinations.
17031703
# If the tip has a volume corresponding to a single destination, then
17041704
# do a single-dispense into that destination.
1705-
for next_vol, next_dest in vol_dest_combo:
1705+
for dispense_vol, dispense_dest in vol_dest_combo:
17061706
if use_single_dispense:
17071707
tip_contents = self.dispense_liquid_class(
1708-
volume=next_vol,
1709-
dest=next_dest,
1708+
volume=dispense_vol,
1709+
dest=dispense_dest,
17101710
source=source,
17111711
transfer_properties=transfer_props,
17121712
transfer_type=tx_comps_executor.TransferType.ONE_TO_MANY,
@@ -1718,8 +1718,8 @@ def _pick_up_tip() -> Tuple[Location, WellCore]:
17181718
)
17191719
else:
17201720
tip_contents = self.dispense_liquid_class_during_multi_dispense(
1721-
volume=next_vol,
1722-
dest=next_dest,
1721+
volume=dispense_vol,
1722+
dest=dispense_dest,
17231723
source=source,
17241724
transfer_properties=transfer_props,
17251725
transfer_type=tx_comps_executor.TransferType.ONE_TO_MANY,
@@ -2145,7 +2145,7 @@ def remove_air_gap_during_transfer_with_liquid_class(
21452145
return
21462146

21472147
correction_volume = dispense_props.correction_by_volume.get_for_volume(
2148-
last_air_gap
2148+
self.get_current_volume() - last_air_gap
21492149
)
21502150
# The minimum flow rate should be air_gap_volume per second
21512151
flow_rate = max(

api/src/opentrons/protocol_api/core/engine/transfer_components_executor.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,9 @@ def aspirate_and_wait(self, volume: float) -> None:
229229
and self._target_well is not None
230230
)
231231
aspirate_props = self._transfer_properties.aspirate
232-
correction_volume = aspirate_props.correction_by_volume.get_for_volume(volume)
232+
correction_volume = aspirate_props.correction_by_volume.get_for_volume(
233+
self._instrument.get_current_volume() + volume
234+
)
233235
self._instrument.aspirate(
234236
location=self._target_location,
235237
well_core=None,
@@ -252,7 +254,7 @@ def dispense_and_wait(
252254
) -> None:
253255
"""Dispense according to dispense properties and wait if enabled."""
254256
correction_volume = dispense_properties.correction_by_volume.get_for_volume(
255-
volume
257+
self._instrument.get_current_volume() - volume
256258
)
257259
self._instrument.dispense(
258260
location=self._target_location,
@@ -895,7 +897,7 @@ def _add_air_gap(
895897
return
896898
aspirate_props = self._transfer_properties.aspirate
897899
correction_volume = aspirate_props.correction_by_volume.get_for_volume(
898-
air_gap_volume
900+
self._instrument.get_current_volume() + air_gap_volume
899901
)
900902
# The minimum flow rate should be air_gap_volume per second
901903
flow_rate = max(

api/src/opentrons/protocol_api/instrument_context.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -570,13 +570,13 @@ def mix( # noqa: C901
570570
dispensing flow rate is calculated as ``rate`` multiplied by
571571
:py:attr:`flow_rate.dispense <flow_rate>`. See
572572
:ref:`new-plunger-flow-rates`.
573-
:param aspirate_flow_rate: The flow rate for each aspirate in the mix, in µL/s.
573+
:param aspirate_flow_rate: The absolute flow rate for each aspirate in the mix, in µL/s.
574574
If this is specified, ``rate`` must not be set.
575-
:param dispense_flow_rate: The flow rate for each dispense in the mix, in µL/s.
575+
:param dispense_flow_rate: The absolute flow rate for each dispense in the mix, in µL/s.
576576
If this is specified, ``rate`` must not be set.
577577
:param aspirate_delay: How long to wait after each aspirate in the mix, in seconds.
578578
:param dispense_delay: How long to wait after each dispense in the mix, in seconds.
579-
:param final_push_out: How much to push out after the final mix repetition. The
579+
:param final_push_out: How much volume to push out after the final mix repetition. The
580580
pipette will not push out after earlier repetitions. If
581581
not specified or ``None``, the pipette will push out the
582582
default non-zero amount. See :ref:`push-out-dispense`.

0 commit comments

Comments
 (0)