Spaces:
Sleeping
Sleeping
added ability to create change and delete experiments
Browse files
app.py
CHANGED
|
@@ -24,6 +24,7 @@ all_graph = False
|
|
| 24 |
temp_mqtt_auto = None
|
| 25 |
rpm_mqtt = None
|
| 26 |
led_mqtt = None
|
|
|
|
| 27 |
|
| 28 |
# if st.session_state.get("channels", None) is not None:
|
| 29 |
# st.session_state["channel_a"] = int(st.session_state["channels"].get("A", 0))
|
|
@@ -79,7 +80,6 @@ else:
|
|
| 79 |
submit_button = st.button("Reconnect")
|
| 80 |
|
| 81 |
|
| 82 |
-
|
| 83 |
# Create the MQTT client
|
| 84 |
# @st.cache_resource
|
| 85 |
def create_mqtt_client(hivemq_host, hivemq_port, hivemq_username, hivemq_password):
|
|
@@ -108,11 +108,13 @@ def on_message_worker(client, userdata, message):
|
|
| 108 |
global temp_mqtt_auto
|
| 109 |
global rpm_mqtt
|
| 110 |
global led_mqtt
|
|
|
|
| 111 |
experiment = data.get("experiment", None)
|
| 112 |
running = data.get("running", [])
|
| 113 |
temp_mqtt_auto = data.get("temperature_automation", None)
|
| 114 |
rpm_mqtt = data.get("stirring", None)
|
| 115 |
led_mqtt = data.get("leds", None)
|
|
|
|
| 116 |
|
| 117 |
def on_message(client, userdata, message):
|
| 118 |
payload = message.payload.decode("utf-8")
|
|
@@ -165,7 +167,7 @@ def get_running_jobs(client, reactor):
|
|
| 165 |
}
|
| 166 |
payload_str = json.dumps(payload)
|
| 167 |
client.publish("pioreactor/control", payload_str)
|
| 168 |
-
|
| 169 |
experiment = None
|
| 170 |
running = []
|
| 171 |
|
|
@@ -177,6 +179,15 @@ def get_running_jobs(client, reactor):
|
|
| 177 |
|
| 178 |
while experiment is None and (time.time() - start_time) < timeout:
|
| 179 |
time.sleep(1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 180 |
|
| 181 |
if st.session_state["jobs"]["temperature_automation"]:
|
| 182 |
if temp_mqtt_auto == "thermostat":
|
|
@@ -192,10 +203,16 @@ def get_running_jobs(client, reactor):
|
|
| 192 |
|
| 193 |
# st.session_state["channels"] = led_mqtt
|
| 194 |
|
| 195 |
-
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 199 |
|
| 200 |
async def get_graph(placeholder):
|
| 201 |
try:
|
|
@@ -245,7 +262,6 @@ if submit_button:
|
|
| 245 |
|
| 246 |
if st.session_state["experiment"] is None:
|
| 247 |
st.error("No experiment assigned to the reactor.")
|
| 248 |
-
st.stop()
|
| 249 |
|
| 250 |
for run in running:
|
| 251 |
st.session_state["jobs"][run] = True
|
|
@@ -266,6 +282,8 @@ if submit_button:
|
|
| 266 |
st.session_state["channel_b"] = int(led_mqtt.get("B", 0))
|
| 267 |
st.session_state["channel_c"] = int(led_mqtt.get("C", 0))
|
| 268 |
st.session_state["channel_d"] = int(led_mqtt.get("D", 0))
|
|
|
|
|
|
|
| 269 |
|
| 270 |
# Save the client to the session state
|
| 271 |
st.session_state["client"] = client
|
|
@@ -275,6 +293,102 @@ if submit_button:
|
|
| 275 |
if st.session_state["experiment"] is not None:
|
| 276 |
st.title(f"Experiment: {st.session_state['experiment']}")
|
| 277 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 278 |
st.header("Running Jobs")
|
| 279 |
|
| 280 |
cols = st.columns(5)
|
|
@@ -1176,59 +1290,60 @@ if st.session_state["experiment"] is not None:
|
|
| 1176 |
st.error("Failed to retrieve data.")
|
| 1177 |
st.stop()
|
| 1178 |
|
| 1179 |
-
|
| 1180 |
-
|
| 1181 |
-
|
| 1182 |
-
|
| 1183 |
-
|
| 1184 |
-
|
| 1185 |
-
|
| 1186 |
-
|
| 1187 |
-
|
| 1188 |
-
|
| 1189 |
-
|
| 1190 |
-
|
| 1191 |
-
|
| 1192 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1193 |
|
| 1194 |
-
|
| 1195 |
-
|
| 1196 |
-
|
| 1197 |
-
|
| 1198 |
-
|
| 1199 |
-
|
| 1200 |
-
|
| 1201 |
-
|
| 1202 |
-
|
| 1203 |
-
|
| 1204 |
-
|
| 1205 |
-
|
| 1206 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1207 |
|
| 1208 |
# Filter the data based on the amount of data requested
|
| 1209 |
# Data is in 4 minute intervals
|
| 1210 |
-
|
| 1211 |
-
df = pd.DataFrame(temp_graph)
|
| 1212 |
-
df = df.set_index("x")
|
| 1213 |
-
|
| 1214 |
-
df2 = pd.DataFrame(od_graph)
|
| 1215 |
-
df2 = df2.set_index("x")
|
| 1216 |
-
|
| 1217 |
-
df3 = pd.DataFrame(norm_od_graph)
|
| 1218 |
-
df3 = df3.set_index("x")
|
| 1219 |
-
|
| 1220 |
-
df4 = pd.DataFrame(growth_rate_graph)
|
| 1221 |
-
df4 = df4.set_index("x")
|
| 1222 |
-
|
| 1223 |
-
placeholder.line_chart(df, x_label="Time", y_label="Temperature (°C)")
|
| 1224 |
-
placeholder2.line_chart(df2, x_label="Time", y_label="OD Reading")
|
| 1225 |
-
placeholder3.line_chart(df3, x_label="Time", y_label="Normalized OD Reading")
|
| 1226 |
-
placeholder4.line_chart(df4, x_label="Time", y_label="Growth Rate")
|
| 1227 |
-
|
| 1228 |
-
st.session_state["df"] = df
|
| 1229 |
-
st.session_state["df2"] = df2
|
| 1230 |
-
st.session_state["df3"] = df3
|
| 1231 |
-
st.session_state["df4"] = df4
|
| 1232 |
|
| 1233 |
time.sleep(REQUEST_INTERVAL)
|
| 1234 |
|
|
|
|
| 24 |
temp_mqtt_auto = None
|
| 25 |
rpm_mqtt = None
|
| 26 |
led_mqtt = None
|
| 27 |
+
experiments = []
|
| 28 |
|
| 29 |
# if st.session_state.get("channels", None) is not None:
|
| 30 |
# st.session_state["channel_a"] = int(st.session_state["channels"].get("A", 0))
|
|
|
|
| 80 |
submit_button = st.button("Reconnect")
|
| 81 |
|
| 82 |
|
|
|
|
| 83 |
# Create the MQTT client
|
| 84 |
# @st.cache_resource
|
| 85 |
def create_mqtt_client(hivemq_host, hivemq_port, hivemq_username, hivemq_password):
|
|
|
|
| 108 |
global temp_mqtt_auto
|
| 109 |
global rpm_mqtt
|
| 110 |
global led_mqtt
|
| 111 |
+
global experiments
|
| 112 |
experiment = data.get("experiment", None)
|
| 113 |
running = data.get("running", [])
|
| 114 |
temp_mqtt_auto = data.get("temperature_automation", None)
|
| 115 |
rpm_mqtt = data.get("stirring", None)
|
| 116 |
led_mqtt = data.get("leds", None)
|
| 117 |
+
experiments = data.get("experiments", [])
|
| 118 |
|
| 119 |
def on_message(client, userdata, message):
|
| 120 |
payload = message.payload.decode("utf-8")
|
|
|
|
| 167 |
}
|
| 168 |
payload_str = json.dumps(payload)
|
| 169 |
client.publish("pioreactor/control", payload_str)
|
| 170 |
+
global experiment
|
| 171 |
experiment = None
|
| 172 |
running = []
|
| 173 |
|
|
|
|
| 179 |
|
| 180 |
while experiment is None and (time.time() - start_time) < timeout:
|
| 181 |
time.sleep(1)
|
| 182 |
+
|
| 183 |
+
if experiment is None:
|
| 184 |
+
st.error("Failed to get info")
|
| 185 |
+
st.session_state["experiment"] = None
|
| 186 |
+
time.sleep(3)
|
| 187 |
+
st.rerun()
|
| 188 |
+
|
| 189 |
+
if experiment != st.session_state["experiment"]:
|
| 190 |
+
st.session_state["experiment"] = experiment
|
| 191 |
|
| 192 |
if st.session_state["jobs"]["temperature_automation"]:
|
| 193 |
if temp_mqtt_auto == "thermostat":
|
|
|
|
| 203 |
|
| 204 |
# st.session_state["channels"] = led_mqtt
|
| 205 |
|
| 206 |
+
if led_mqtt is not None:
|
| 207 |
+
st.session_state["channel_a"] = int(led_mqtt.get("A", 0))
|
| 208 |
+
st.session_state["channel_b"] = int(led_mqtt.get("B", 0))
|
| 209 |
+
st.session_state["channel_c"] = int(led_mqtt.get("C", 0))
|
| 210 |
+
st.session_state["channel_d"] = int(led_mqtt.get("D", 0))
|
| 211 |
+
|
| 212 |
+
st.session_state["experiments"] = experiments
|
| 213 |
+
|
| 214 |
+
for run in running:
|
| 215 |
+
st.session_state["jobs"][run] = True
|
| 216 |
|
| 217 |
async def get_graph(placeholder):
|
| 218 |
try:
|
|
|
|
| 262 |
|
| 263 |
if st.session_state["experiment"] is None:
|
| 264 |
st.error("No experiment assigned to the reactor.")
|
|
|
|
| 265 |
|
| 266 |
for run in running:
|
| 267 |
st.session_state["jobs"][run] = True
|
|
|
|
| 282 |
st.session_state["channel_b"] = int(led_mqtt.get("B", 0))
|
| 283 |
st.session_state["channel_c"] = int(led_mqtt.get("C", 0))
|
| 284 |
st.session_state["channel_d"] = int(led_mqtt.get("D", 0))
|
| 285 |
+
|
| 286 |
+
st.session_state["experiments"] = experiments
|
| 287 |
|
| 288 |
# Save the client to the session state
|
| 289 |
st.session_state["client"] = client
|
|
|
|
| 293 |
if st.session_state["experiment"] is not None:
|
| 294 |
st.title(f"Experiment: {st.session_state['experiment']}")
|
| 295 |
|
| 296 |
+
with st.form("experiment_form"):
|
| 297 |
+
new_name = st.text_input("New Experiment Name")
|
| 298 |
+
submit_new_experiment = st.form_submit_button("Create New Experiment")
|
| 299 |
+
|
| 300 |
+
change_experiment_submit = False
|
| 301 |
+
delete_experiment = False
|
| 302 |
+
|
| 303 |
+
with st.form("experiment_edit"):
|
| 304 |
+
if len(st.session_state["experiments"]) > 0:
|
| 305 |
+
experiment_change = st.selectbox("Select Experiment", st.session_state["experiments"])
|
| 306 |
+
cols = st.columns(2)
|
| 307 |
+
with cols[0]:
|
| 308 |
+
change_experiment_submit = st.form_submit_button("Change Experiment")
|
| 309 |
+
with cols[1]:
|
| 310 |
+
delete_experiment = st.form_submit_button("Delete Experiment")
|
| 311 |
+
else:
|
| 312 |
+
st.write("No experiments available.")
|
| 313 |
+
st.form_submit_button("Nothing Button")
|
| 314 |
+
|
| 315 |
+
if submit_new_experiment:
|
| 316 |
+
payload = {
|
| 317 |
+
"command": "new_experiment",
|
| 318 |
+
"experiment": new_name,
|
| 319 |
+
"reactor": reactor
|
| 320 |
+
}
|
| 321 |
+
payload_str = json.dumps(payload)
|
| 322 |
+
|
| 323 |
+
st.session_state["client"].loop_start()
|
| 324 |
+
st.session_state["client"].publish("pioreactor/control", payload_str, qos=1)
|
| 325 |
+
|
| 326 |
+
get_running_jobs(st.session_state["client"], reactor)
|
| 327 |
+
|
| 328 |
+
if new_name in st.session_state["experiments"]:
|
| 329 |
+
st.success("Experiment created successfully!")
|
| 330 |
+
else:
|
| 331 |
+
st.error("Failed to create experiment.")
|
| 332 |
+
|
| 333 |
+
|
| 334 |
+
st.session_state["client"].loop_stop()
|
| 335 |
+
|
| 336 |
+
time.sleep(3)
|
| 337 |
+
st.rerun()
|
| 338 |
+
|
| 339 |
+
if change_experiment_submit:
|
| 340 |
+
payload = {
|
| 341 |
+
"command": "change_experiment",
|
| 342 |
+
"experiment": st.session_state["experiment"],
|
| 343 |
+
"experiment_new": experiment_change,
|
| 344 |
+
"reactor": reactor
|
| 345 |
+
}
|
| 346 |
+
payload_str = json.dumps(payload)
|
| 347 |
+
|
| 348 |
+
st.session_state["client"].loop_start()
|
| 349 |
+
st.session_state["client"].publish("pioreactor/control", payload_str, qos=1)
|
| 350 |
+
|
| 351 |
+
time.sleep(3)
|
| 352 |
+
|
| 353 |
+
get_running_jobs(st.session_state["client"], reactor)
|
| 354 |
+
|
| 355 |
+
if experiment_change == st.session_state["experiment"]:
|
| 356 |
+
st.success("Experiment changed successfully!")
|
| 357 |
+
|
| 358 |
+
else:
|
| 359 |
+
st.error("Failed to change experiment.")
|
| 360 |
+
|
| 361 |
+
st.info(f"Experiment name changed to {experiment_change} from {st.session_state['experiment']}")
|
| 362 |
+
|
| 363 |
+
st.session_state["client"].loop_stop()
|
| 364 |
+
|
| 365 |
+
time.sleep(3)
|
| 366 |
+
st.rerun()
|
| 367 |
+
|
| 368 |
+
if delete_experiment:
|
| 369 |
+
payload = {
|
| 370 |
+
"command": "delete_experiment",
|
| 371 |
+
"experiment": experiment_change,
|
| 372 |
+
"reactor": reactor
|
| 373 |
+
}
|
| 374 |
+
payload_str = json.dumps(payload)
|
| 375 |
+
|
| 376 |
+
time.sleep(1)
|
| 377 |
+
|
| 378 |
+
st.session_state["client"].loop_start()
|
| 379 |
+
st.session_state["client"].publish("pioreactor/control", payload_str, qos=1)
|
| 380 |
+
|
| 381 |
+
get_running_jobs(st.session_state["client"], reactor)
|
| 382 |
+
|
| 383 |
+
if experiment_change not in st.session_state["experiments"]:
|
| 384 |
+
st.success("Experiment deleted successfully!")
|
| 385 |
+
else:
|
| 386 |
+
st.error("Failed to delete experiment.")
|
| 387 |
+
|
| 388 |
+
st.session_state["client"].loop_stop()
|
| 389 |
+
time.sleep(3)
|
| 390 |
+
st.rerun()
|
| 391 |
+
|
| 392 |
st.header("Running Jobs")
|
| 393 |
|
| 394 |
cols = st.columns(5)
|
|
|
|
| 1290 |
st.error("Failed to retrieve data.")
|
| 1291 |
st.stop()
|
| 1292 |
|
| 1293 |
+
if len(temp_graph) != 0:
|
| 1294 |
+
|
| 1295 |
+
for temp in temp_graph:
|
| 1296 |
+
utc_time = datetime.strptime(temp["x"], "%Y-%m-%dT%H:%M:%S.%fZ")
|
| 1297 |
+
local_tz = pytz.timezone("America/New_York")
|
| 1298 |
+
utc_time = utc_time.replace(tzinfo=pytz.utc)
|
| 1299 |
+
local_time = utc_time.astimezone(local_tz)
|
| 1300 |
+
temp["x"] = local_time.strftime("%Y-%m-%d %H:%M:%S")
|
| 1301 |
+
df = pd.DataFrame(temp_graph)
|
| 1302 |
+
df = df.set_index("x")
|
| 1303 |
+
placeholder.line_chart(df, x_label="Time", y_label="Temperature (°C)")
|
| 1304 |
+
st.session_state["df"] = df
|
| 1305 |
+
|
| 1306 |
+
if len(od_graph) != 0:
|
| 1307 |
+
|
| 1308 |
+
for od in od_graph:
|
| 1309 |
+
utc_time = datetime.strptime(od["x"], "%Y-%m-%dT%H:%M:%S.%fZ")
|
| 1310 |
+
local_tz = pytz.timezone("America/New_York")
|
| 1311 |
+
utc_time = utc_time.replace(tzinfo=pytz.utc)
|
| 1312 |
+
local_time = utc_time.astimezone(local_tz)
|
| 1313 |
+
od["x"] = local_time.strftime("%Y-%m-%d %H:%M:%S")
|
| 1314 |
+
df2 = pd.DataFrame(od_graph)
|
| 1315 |
+
df2 = df2.set_index("x")
|
| 1316 |
+
placeholder2.line_chart(df2, x_label="Time", y_label="OD Reading")
|
| 1317 |
+
st.session_state["df2"] = df2
|
| 1318 |
+
|
| 1319 |
+
if len(norm_od_graph) != 0:
|
| 1320 |
|
| 1321 |
+
for norm_od in norm_od_graph:
|
| 1322 |
+
utc_time = datetime.strptime(norm_od["x"], "%Y-%m-%dT%H:%M:%S.%fZ")
|
| 1323 |
+
local_tz = pytz.timezone("America/New_York")
|
| 1324 |
+
utc_time = utc_time.replace(tzinfo=pytz.utc)
|
| 1325 |
+
local_time = utc_time.astimezone(local_tz)
|
| 1326 |
+
norm_od["x"] = local_time.strftime("%Y-%m-%d %H:%M:%S")
|
| 1327 |
+
df3 = pd.DataFrame(norm_od_graph)
|
| 1328 |
+
df3 = df3.set_index("x")
|
| 1329 |
+
placeholder3.line_chart(df3, x_label="Time", y_label="Normalized OD Reading")
|
| 1330 |
+
st.session_state["df3"] = df3
|
| 1331 |
+
|
| 1332 |
+
if len(growth_rate_graph) != 0:
|
| 1333 |
+
|
| 1334 |
+
for growth_rate in growth_rate_graph:
|
| 1335 |
+
utc_time = datetime.strptime(growth_rate["x"], "%Y-%m-%dT%H:%M:%S.%fZ")
|
| 1336 |
+
local_tz = pytz.timezone("America/New_York")
|
| 1337 |
+
utc_time = utc_time.replace(tzinfo=pytz.utc)
|
| 1338 |
+
local_time = utc_time.astimezone(local_tz)
|
| 1339 |
+
growth_rate["x"] = local_time.strftime("%Y-%m-%d %H:%M:%S")
|
| 1340 |
+
df4 = pd.DataFrame(growth_rate_graph)
|
| 1341 |
+
df4 = df4.set_index("x")
|
| 1342 |
+
placeholder4.line_chart(df4, x_label="Time", y_label="Growth Rate")
|
| 1343 |
+
st.session_state["df4"] = df4
|
| 1344 |
|
| 1345 |
# Filter the data based on the amount of data requested
|
| 1346 |
# Data is in 4 minute intervals
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1347 |
|
| 1348 |
time.sleep(REQUEST_INTERVAL)
|
| 1349 |
|