Skip to content

Commit a3dff9c

Browse files
committed
Script to pull unique run logs from ABR robots
1 parent c142da1 commit a3dff9c

File tree

3 files changed

+149
-0
lines changed

3 files changed

+149
-0
lines changed

hardware-testing/hardware_testing/abr_tools/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
"""ABR Robot IPs."""
2+
3+
ABR_IPS = [
4+
"10.14.12.159",
5+
"10.14.12.161",
6+
"10.14.12.126",
7+
"10.14.12.112",
8+
"10.14.12.124",
9+
"10.14.12.163",
10+
"10.14.12.162",
11+
"10.14.12.165",
12+
"10.14.12.164",
13+
"10.14.12.168",
14+
"10.14.12.167",
15+
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
"""ABR Run Log Pull."""
2+
from .abr_robots import ABR_IPS
3+
import argparse
4+
import os
5+
import json
6+
import traceback
7+
import requests
8+
from typing import Set, Dict, Any
9+
10+
11+
def get_run_ids_from_storage(storage_directory: str) -> Set[str]:
12+
"""Read all files in long term storage directory and read run id. Add run id to a set. Return run id set."""
13+
os.makedirs(storage_directory, exist_ok=True)
14+
list_of_files = os.listdir(storage_directory)
15+
run_ids = set()
16+
for this_file in list_of_files:
17+
read_file = os.path.join(storage_directory, this_file)
18+
try:
19+
file_results = json.load(open(read_file))
20+
except json.JSONDecodeError:
21+
print(f"Ignoring unparsable file {read_file}.")
22+
continue
23+
run_id = file_results["run_id"]
24+
run_ids.add(run_id)
25+
return run_ids
26+
27+
28+
def get_unseen_run_ids(runs: Set[str], runs_from_storage: Set[str]) -> Set[str]:
29+
"""Subtracts runs from storage from current runs being read."""
30+
runs_to_save = runs - runs_from_storage
31+
return runs_to_save
32+
33+
34+
def get_run_ids_from_robot(ip: str) -> Set[str]:
35+
"""Get all completed runs from each robot."""
36+
run_ids = set()
37+
response = requests.get(
38+
f"http://{ip}:31950/runs", headers={"opentrons-version": "3"}
39+
)
40+
run_data = response.json()
41+
run_list = run_data["data"]
42+
for run in run_list:
43+
run_id = run["id"]
44+
if not run["current"]:
45+
run_ids.add(run_id)
46+
return run_ids
47+
48+
49+
def get_run_data(one_run: Any, ip: str) -> Dict[str, Any]:
50+
response = requests.get(
51+
f"http://{ip}:31950/runs/{one_run}/commands",
52+
headers={"opentrons-version": "3"},
53+
params={"cursor": 0, "pageLength": 0},
54+
)
55+
data = response.json()
56+
command_count = data["meta"]["totalLength"]
57+
page_length = 100
58+
commands = list()
59+
run = dict()
60+
for cursor in range(0, command_count, page_length):
61+
response = requests.get(
62+
f"http://{ip}:31950/runs/{one_run}/commands",
63+
headers={"opentrons-version": "3"},
64+
params={"cursor": cursor, "pageLength": page_length},
65+
)
66+
command_data = response.json()
67+
commands.extend(command_data["data"])
68+
run["commands"] = commands
69+
response = requests.get(
70+
f"http://{ip}:31950/runs/{one_run}", headers={"opentrons-version": "3"}
71+
)
72+
run_meta_data = response.json()
73+
protocol_id = run_meta_data["data"]["protocolId"]
74+
run.update(run_meta_data["data"])
75+
response = requests.get(
76+
f"http://{ip}:31950/protocols/{protocol_id}", headers={"opentrons-version": "3"}
77+
)
78+
protocol_data = response.json()
79+
run["protocol"] = protocol_data["data"]
80+
response = requests.get(
81+
f"http://{ip}:31950/health", headers={"opentrons-version": "3"}
82+
)
83+
health_data = response.json()
84+
robot_name = health_data["name"]
85+
try:
86+
robot_serial = health_data["robot_serial"]
87+
except:
88+
robot_serial = "unknown"
89+
run["robot_name"] = robot_name
90+
run["run_id"] = one_run
91+
run["robot_serial"] = robot_serial
92+
return run
93+
94+
95+
def save_runs(runs_to_save: Set[str], ip: str, storage_directory: str) -> None:
96+
for a_run in runs_to_save:
97+
data = get_run_data(a_run, ip)
98+
robot_name = data["robot_name"]
99+
data_file_name = data["robot_name"] + "_" + data["run_id"] + ".json"
100+
json.dump(data, open(os.path.join(storage_directory, data_file_name), mode="w"))
101+
print(
102+
f"Saved {len(runs_to_save)} run(s) from robot {robot_name} with IP address {ip}."
103+
)
104+
pass
105+
106+
107+
def get_all_run_logs(storage_directory: str):
108+
"""Connect to each ABR robot to read run log data.
109+
Read each robot's list of unique run log IDs and compare them to all IDs for all of the runs in storage.
110+
Any ID that is not in storage, download the run log and put it in storage."""
111+
112+
runs_from_storage = get_run_ids_from_storage(storage_directory)
113+
for ip in ABR_IPS:
114+
try:
115+
runs = get_run_ids_from_robot(ip)
116+
runs_to_save = get_unseen_run_ids(runs, runs_from_storage)
117+
save_runs(runs_to_save, ip, storage_directory)
118+
except Exception:
119+
print(f"Failed to read IP address: {ip}.")
120+
traceback.print_exc()
121+
pass
122+
123+
124+
if __name__ == "__main__":
125+
parser = argparse.ArgumentParser(description="Pulls run logs from ABR robots.")
126+
parser.add_argument(
127+
"storage_directory",
128+
metavar="STORAGE_DIRECTORY",
129+
type=str,
130+
nargs=1,
131+
help="Path to long term storage directory for run logs.",
132+
)
133+
args = parser.parse_args()
134+
get_all_run_logs(args.storage_directory[0])

0 commit comments

Comments
 (0)