Skip to content

Commit f6099c4

Browse files
authored
Correct HS Time Calculation and Print Statements (#15005)
<!-- Thanks for taking the time to open a pull request! Please make sure you've read the "Opening Pull Requests" section of our Contributing Guide: https://github.com/Opentrons/opentrons/blob/edge/CONTRIBUTING.md#opening-pull-requests To ensure your code is reviewed quickly and thoroughly, please fill out the sections below to the best of your ability! --> # Overview Concise print statements and HS on time calculation correction. # Test Plan Tested on ABR robots. # Changelog Previously, the heater shaker temperature on time was linked to the shaker on time. This has been corrected to reference the correct command string. If the heatershaker is not deactivated, the on time is calculated with the protocol end time stamp. Changed print statements for get robot logs and abr_google_drive to make it more obvious to the user if there is an error or not. # Review requests <!-- Describe any requests for your reviewers here. --> # Risk assessment <!-- Carefully go over your pull request and look at the other parts of the codebase it may affect. Look for the possibility, even if you think it's small, that your change may affect some other part of the system - for instance, changing return tip behavior in protocol may also change the behavior of labware calibration. Identify the other parts of the system your codebase may affect, so that in addition to your own review and testing, other people who may not have the system internalized as much as you can focus their attention and testing there. -->
1 parent bd1f8da commit f6099c4

File tree

5 files changed

+64
-40
lines changed

5 files changed

+64
-40
lines changed

abr-testing/abr_testing/automation/google_drive_tool.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import webbrowser
55
import mimetypes
66
from oauth2client.service_account import ServiceAccountCredentials # type: ignore[import]
7+
import googleapiclient # type: ignore[import]
78
from googleapiclient.discovery import build
89
from googleapiclient.http import MediaFileUpload
910

@@ -58,7 +59,6 @@ def list_folder(self, delete: Any = False) -> Set[str]:
5859
break
5960
if not file_names:
6061
print("No folders or files found in Google Drive.")
61-
print(f"{len(file_names)} item(s) in Google Drive")
6262
return file_names
6363

6464
def delete_files(self, file_or_folder_id: str) -> None:
@@ -98,18 +98,22 @@ def upload_missing_files(self, storage_directory: str) -> None:
9898
file for file in os.listdir(storage_directory) if file.endswith(".json")
9999
)
100100
missing_files = local_files_json - set(google_drive_files_json)
101-
print(f"Missing files: {len(missing_files)}")
102101
# Upload missing files.
103102
uploaded_files = []
104103
for file in missing_files:
105104
file_path = os.path.join(storage_directory, file)
106105
uploaded_file_id = google_drive.upload_file(self, file_path)
107-
self.share_permissions(uploaded_file_id)
108106
uploaded_files.append(
109107
{"name": os.path.basename(file_path), "id": uploaded_file_id}
110108
)
109+
try:
110+
self.share_permissions(uploaded_file_id)
111+
except googleapiclient.errors.HttpError:
112+
continue
113+
111114
# Fetch the updated file list after all files are uploaded
112115
files = google_drive.list_folder(self)
116+
113117
file_names = [file for file in files]
114118
for uploaded_file in uploaded_files:
115119
this_name = uploaded_file["name"]
@@ -121,6 +125,7 @@ def upload_missing_files(self, storage_directory: str) -> None:
121125
print(
122126
f"File '{this_name}' was not found in the list of files after uploading."
123127
)
128+
print(f"{len(files)} item(s) in Google Drive")
124129

125130
def open_folder(self) -> Optional[str]:
126131
"""Open folder in web browser."""

abr-testing/abr_testing/automation/google_sheets_tool.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import gspread # type: ignore[import]
33
import socket
44
import httplib2
5+
import time as t
56
from datetime import datetime
67
from oauth2client.service_account import ServiceAccountCredentials # type: ignore[import]
78
from typing import Dict, List, Any, Set, Tuple
@@ -71,6 +72,10 @@ def write_to_row(self, data: List) -> None:
7172
print("UNABLE TO CONNECT TO SERVER!!, CHECK CONNECTION")
7273
except Exception as error:
7374
print(error.__traceback__)
75+
except gspread.exceptions.APIError:
76+
print("Write quotes exceeded. Waiting 30 sec before writing.")
77+
t.sleep(30)
78+
self.worksheet.insert_row(data, index=self.row_index)
7479

7580
def delete_row(self, row_index: int) -> None:
7681
"""Delete Row from google sheet."""
@@ -94,7 +99,7 @@ def get_column(self, column_number: int) -> Set[str]:
9499
def get_index_row(self) -> int:
95100
"""Check for the next available row to write too."""
96101
row_index = len(self.get_column(1))
97-
print("Row Index: ", row_index)
102+
print(f"Row Index: {row_index} recorded on google sheet.")
98103
return row_index
99104

100105
def update_row_index(self) -> None:

abr-testing/abr_testing/data_collection/abr_calibration_logs.py

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import json
66
import gspread # type: ignore[import]
77
import sys
8+
import time as t
89
from abr_testing.data_collection import read_robot_logs
910
from abr_testing.automation import google_drive_tool, google_sheets_tool
1011

@@ -18,16 +19,20 @@ def check_for_duplicates(
1819
headers: List[str],
1920
) -> Union[List[str], None]:
2021
"""Check google sheet for duplicates."""
22+
t.sleep(5)
2123
serials = google_sheet.get_column(col_1)
2224
modify_dates = google_sheet.get_column(col_2)
23-
# check for complete calibration.
24-
if len(row[-1]) > 0:
25-
for serial, modify_date in zip(serials, modify_dates):
26-
if row[col_1 - 1] == serial and row[col_2 - 1] == modify_date:
27-
print(f"Skipped row for instrument {serial}. Already on Google Sheet.")
28-
return None
29-
read_robot_logs.write_to_sheets(sheet_location, google_sheet, row, headers)
30-
print(f"Writing calibration for: {serial}")
25+
# Check for calibration time stamp.
26+
if row[-1] is not None:
27+
if len(row[-1]) > 0:
28+
for serial, modify_date in zip(serials, modify_dates):
29+
if row[col_1 - 1] == serial and row[col_2 - 1] == modify_date:
30+
print(
31+
f"Skipped row for instrument {serial}. Already on Google Sheet."
32+
)
33+
return None
34+
read_robot_logs.write_to_sheets(sheet_location, google_sheet, row, headers)
35+
print(f"Writing calibration for: {row[7]}")
3136
return row
3237

3338

@@ -206,15 +211,10 @@ def upload_calibration_offsets(
206211
if ip_or_all == "ALL":
207212
ip_address_list = ip_file["ip_address_list"]
208213
for ip in ip_address_list:
209-
print(ip)
210-
try:
211-
saved_file_path, calibration = read_robot_logs.get_calibration_offsets(
212-
ip, storage_directory
213-
)
214-
upload_calibration_offsets(calibration, storage_directory)
215-
except Exception:
216-
print(f"ERROR: Failed to read IP address: {ip}")
217-
continue
214+
saved_file_path, calibration = read_robot_logs.get_calibration_offsets(
215+
ip, storage_directory
216+
)
217+
upload_calibration_offsets(calibration, storage_directory)
218218
else:
219219
saved_file_path, calibration = read_robot_logs.get_calibration_offsets(
220220
ip_or_all, storage_directory

abr-testing/abr_testing/data_collection/get_run_logs.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -104,13 +104,10 @@ def get_all_run_logs(storage_directory: str) -> None:
104104
ip_address_list = ip_file["ip_address_list"]
105105
runs_from_storage = read_robot_logs.get_run_ids_from_google_drive(google_drive)
106106
for ip in ip_address_list:
107-
try:
108-
runs = get_run_ids_from_robot(ip)
109-
runs_to_save = read_robot_logs.get_unseen_run_ids(runs, runs_from_storage)
110-
save_runs(runs_to_save, ip, storage_directory)
111-
google_drive.upload_missing_files(storage_directory)
112-
except Exception:
113-
print(f"ERROR: Failed to read IP address: {ip}.")
107+
runs = get_run_ids_from_robot(ip)
108+
runs_to_save = read_robot_logs.get_unseen_run_ids(runs, runs_from_storage)
109+
save_runs(runs_to_save, ip, storage_directory)
110+
google_drive.upload_missing_files(storage_directory)
114111

115112

116113
if __name__ == "__main__":

abr-testing/abr_testing/data_collection/read_robot_logs.py

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import time as t
1313
import json
1414
import requests
15+
import sys
1516

1617

1718
def lpc_data(file_results: Dict[str, Any], protocol_info: Dict) -> List[Dict[str, Any]]:
@@ -72,9 +73,10 @@ def hs_commands(file_results: Dict[str, Any]) -> Dict[str, float]:
7273
hs_home_count: float = 0.0
7374
hs_speed: float = 0.0
7475
hs_rotations: Dict[str, float] = dict()
75-
hs_temps: Dict[str, float] = dict()
76+
hs_temps: Dict[float, float] = dict()
7677
temp_time = None
7778
shake_time = None
79+
deactivate_time = None
7880
for command in commandData:
7981
commandType = command["commandType"]
8082
# Heatershaker
@@ -87,17 +89,21 @@ def hs_commands(file_results: Dict[str, Any]) -> Dict[str, float]:
8789
# Home count
8890
elif commandType == "heaterShaker/deactivateShaker":
8991
hs_home_count += 1
92+
shake_deactivate_time = datetime.strptime(
93+
command.get("startedAt", ""), "%Y-%m-%dT%H:%M:%S.%f%z"
94+
)
95+
if shake_time is not None and shake_deactivate_time > shake_time:
96+
shake_duration = (shake_deactivate_time - shake_time).total_seconds()
97+
hs_rotations[hs_speed] = hs_rotations.get(hs_speed, 0.0) + (
98+
(hs_speed * shake_duration) / 60
99+
)
100+
elif commandType == "heaterShaker/deactivateHeater":
90101
deactivate_time = datetime.strptime(
91102
command.get("startedAt", ""), "%Y-%m-%dT%H:%M:%S.%f%z"
92103
)
93104
if temp_time is not None and deactivate_time > temp_time:
94105
temp_duration = (deactivate_time - temp_time).total_seconds()
95106
hs_temps[hs_temp] = hs_temps.get(hs_temp, 0.0) + temp_duration
96-
if shake_time is not None and deactivate_time > shake_time:
97-
shake_duration = (deactivate_time - shake_time).total_seconds()
98-
hs_rotations[hs_speed] = hs_rotations.get(hs_speed, 0.0) + (
99-
(hs_speed * shake_duration) / 60
100-
)
101107
# of Rotations
102108
elif commandType == "heaterShaker/setAndWaitForShakeSpeed":
103109
hs_speed = command["params"]["rpm"]
@@ -111,6 +117,13 @@ def hs_commands(file_results: Dict[str, Any]) -> Dict[str, float]:
111117
temp_time = datetime.strptime(
112118
command.get("completedAt", ""), "%Y-%m-%dT%H:%M:%S.%f%z"
113119
)
120+
if temp_time is not None and deactivate_time is None:
121+
# If heater shaker module is not deactivated, protocol completedAt time stamp used.
122+
protocol_end = datetime.strptime(
123+
file_results.get("completedAt", ""), "%Y-%m-%dT%H:%M:%S.%f%z"
124+
)
125+
temp_duration = (protocol_end - temp_time).total_seconds()
126+
hs_temps[hs_temp] = hs_temps.get(hs_temp, 0.0) + temp_duration
114127
hs_latch_sets = hs_latch_count / 2 # one set of open/close
115128
hs_total_rotations = sum(hs_rotations.values())
116129
hs_total_temp_time = sum(hs_temps.values())
@@ -254,7 +267,7 @@ def create_abr_data_sheet(
254267
file_name_csv = file_name + ".csv"
255268
sheet_location = os.path.join(storage_directory, file_name_csv)
256269
if os.path.exists(sheet_location):
257-
print(f"File {sheet_location} located. Not overwriting.")
270+
return sheet_location
258271
else:
259272
with open(sheet_location, "w") as csvfile:
260273
writer = csv.DictWriter(csvfile, fieldnames=headers)
@@ -368,7 +381,6 @@ def get_run_ids_from_storage(storage_directory: str) -> Set[str]:
368381
def get_unseen_run_ids(runs: Set[str], runs_from_storage: Set[str]) -> Set[str]:
369382
"""Subtracts runs from storage from current runs being read."""
370383
runs_to_save = runs - runs_from_storage
371-
print(f"There are {str(len(runs_to_save))} new run(s) to save.")
372384
return runs_to_save
373385

374386

@@ -406,7 +418,7 @@ def write_to_sheets(
406418
google_sheet.write_header(headers)
407419
google_sheet.update_row_index()
408420
google_sheet.write_to_row(row_list)
409-
t.sleep(5) # Sleep added to avoid API error.
421+
t.sleep(5)
410422

411423

412424
def get_calibration_offsets(
@@ -415,9 +427,14 @@ def get_calibration_offsets(
415427
"""Connect to robot via ip and get calibration data."""
416428
calibration = dict()
417429
# Robot Information [Name, Software Version]
418-
response = requests.get(
419-
f"http://{ip}:31950/health", headers={"opentrons-version": "3"}
420-
)
430+
try:
431+
response = requests.get(
432+
f"http://{ip}:31950/health", headers={"opentrons-version": "3"}
433+
)
434+
print(f"Connected to {ip}")
435+
except Exception:
436+
print(f"ERROR: Failed to read IP address: {ip}")
437+
sys.exit()
421438
health_data = response.json()
422439
robot_name = health_data.get("name", "")
423440
api_version = health_data.get("api_version", "")

0 commit comments

Comments
 (0)