linx5o commited on
Commit
38d1a35
1 Parent(s): bc4c471

inplemented functionaility for custom user

Browse files
Files changed (1) hide show
  1. app.py +514 -0
app.py ADDED
@@ -0,0 +1,514 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import paho.mqtt.client as mqtt
3
+ import os
4
+ import json
5
+ import time
6
+
7
+ HOST = os.getenv("host")
8
+ PORT = os.getenv("port")
9
+ USERNAME = os.getenv("username")
10
+ PASSWORD = os.getenv("password")
11
+ PIOREACTOR = os.getenv("pioreactor")
12
+
13
+ HOST_gr = gr.State("Host", HOST)
14
+ PORT_gr = gr.State("Port", PORT)
15
+ USERNAME_gr = gr.State("Username", USERNAME)
16
+ PASSWORD_gr = gr.State("Password", PASSWORD)
17
+ PIOREACTOR_gr = gr.State("Pioreactor", PIOREACTOR)
18
+
19
+ client = None
20
+ client_custom = None
21
+
22
+
23
+ def on_connect(client, userdata, flags, rc):
24
+ print("Connected with result code "+str(rc))
25
+
26
+ def create_client(host, port, username, password):
27
+ client = mqtt.Client()
28
+ client.username_pw_set(username, password)
29
+ client.tls_set(tls_version=mqtt.ssl.PROTOCOL_TLS)
30
+ client.on_connect = on_connect
31
+ client.connect(host, port)
32
+ client.loop_start()
33
+ return client
34
+
35
+ def on_message_worker(client, userdata, message):
36
+ payload = message.payload.decode("utf-8")
37
+ data = json.loads(payload)
38
+ global experiment
39
+ global running
40
+ global temp_mqtt_auto
41
+ global rpm_mqtt
42
+ global led_mqtt
43
+ global experiments
44
+ experiment = data.get("experiment", None)
45
+ running = data.get("running", [])
46
+ temp_mqtt_auto = data.get("temperature_automation", None)
47
+ rpm_mqtt = data.get("stirring", None)
48
+ led_mqtt = data.get("leds", None)
49
+ experiments = data.get("experiments", [])
50
+
51
+
52
+ def store_client():
53
+ global client
54
+ global HOST
55
+ global PORT
56
+ global USERNAME
57
+ global PASSWORD
58
+ client = create_client(HOST, PORT, USERNAME, PASSWORD)
59
+
60
+ def custom_client(host, port, username, password):
61
+ global client_custom
62
+ client_custom = create_client(host, port, username, password)
63
+
64
+ def stirring(rpm, host, port, username, password, pioreactor, experiment, state):
65
+ global client_custom
66
+ if client_custom is None:
67
+ custom_client(host, port, username, password)
68
+
69
+ if state == "start":
70
+ payload = {
71
+ "command": "start_stirring",
72
+ "experiment": experiment,
73
+ "reactor": pioreactor,
74
+ "rpm": rpm
75
+ }
76
+ client_custom.publish(f"pioreactor/control", json.dumps(payload))
77
+ elif state == "stop":
78
+ payload = {
79
+ "command": "stop_stirring",
80
+ "experiment": experiment,
81
+ "reactor": pioreactor
82
+ }
83
+ client_custom.publish(f"pioreactor/control", json.dumps(payload))
84
+ elif state == "update":
85
+ payload = {
86
+ "command": "update_stirring",
87
+ "experiment": experiment,
88
+ "reactor": pioreactor,
89
+ "rpm": rpm
90
+ }
91
+ client_custom.publish(f"pioreactor/control", json.dumps(payload))
92
+ else:
93
+ print("Invalid state")
94
+
95
+ def toggle_temperature_input(selected_option):
96
+ # Show the temperature slider only if "Heat To Temp" is selected
97
+ return gr.update(visible=selected_option == "Heat To Temp")
98
+
99
+ def temp_automation(temperature, host, port, username, password, pioreactor, experiment, state, option):
100
+ global client_custom
101
+ if client_custom is None:
102
+ custom_client(host, port, username, password)
103
+
104
+ payload_options = "thermostat" if option == "Heat To Temp" else "only_record_temperature"
105
+
106
+ if state == "start":
107
+ payload = {
108
+ "command": "set_temperature_automation",
109
+ "experiment": experiment,
110
+ "reactor": pioreactor,
111
+ "temp": temperature,
112
+ "automation": payload_options
113
+ }
114
+ client_custom.publish(f"pioreactor/control", json.dumps(payload))
115
+ elif state == "stop":
116
+ payload = {
117
+ "command": "temp_update",
118
+ "experiment": experiment,
119
+ "reactor": pioreactor,
120
+ "settings": {
121
+ "$state": "disconnected"
122
+ }
123
+ }
124
+ client_custom.publish(f"pioreactor/control", json.dumps(payload))
125
+ elif state == "update":
126
+ payload = {
127
+ "command": "temp_update",
128
+ "experiment": experiment,
129
+ "reactor": pioreactor,
130
+ "settings": {
131
+ "target_temperature": temperature
132
+ }
133
+ }
134
+ client_custom.publish(f"pioreactor/control", json.dumps(payload))
135
+ elif state == "restart":
136
+ payload = {
137
+ "command": "temp_restart",
138
+ "experiment": experiment,
139
+ "reactor": pioreactor,
140
+ "automation": payload_options,
141
+ "temp": temperature
142
+ }
143
+ client_custom.publish(f"pioreactor/control", json.dumps(payload))
144
+ else:
145
+ print("Invalid state")
146
+
147
+ def od(host, port, username, password, pioreactor, experiment, state):
148
+ global client_custom
149
+ if client_custom is None:
150
+ custom_client(host, port, username, password)
151
+
152
+ if state == "start":
153
+ payload = {
154
+ "command": "start_od_reading",
155
+ "experiment": experiment,
156
+ "reactor": pioreactor
157
+ }
158
+ client_custom.publish(f"pioreactor/control", json.dumps(payload))
159
+ elif state == "stop":
160
+ payload = {
161
+ "command": "stop_od_reading",
162
+ "experiment": experiment,
163
+ "reactor": pioreactor
164
+ }
165
+ client_custom.publish(f"pioreactor/control", json.dumps(payload))
166
+ else:
167
+ print("Invalid state")
168
+
169
+ def grf(host, port, username, password, pioreactor, experiment, state):
170
+ global client_custom
171
+ if client_custom is None:
172
+ custom_client(host, port, username, password)
173
+
174
+ if state == "start":
175
+ payload = {
176
+ "command": "start_growth_rate",
177
+ "experiment": experiment,
178
+ "reactor": pioreactor
179
+ }
180
+ client_custom.publish(f"pioreactor/control", json.dumps(payload))
181
+ elif state == "stop":
182
+ payload = {
183
+ "command": "stop_growth_rate",
184
+ "experiment": experiment,
185
+ "reactor": pioreactor
186
+ }
187
+ client_custom.publish(f"pioreactor/control", json.dumps(payload))
188
+ else:
189
+ print("Invalid state")
190
+
191
+ def led1fn(led1, host, port, username, password, pioreactor, experiment):
192
+ global client_custom
193
+ if client_custom is None:
194
+ custom_client(host, port, username, password)
195
+
196
+ payload = {
197
+ "command": "set_led_intensity",
198
+ "experiment": experiment,
199
+ "reactor": pioreactor,
200
+ "led": "A",
201
+ "brightness": led1
202
+ }
203
+ client_custom.publish(f"pioreactor/control", json.dumps(payload))
204
+
205
+ def led2fn(led2, host, port, username, password, pioreactor, experiment):
206
+ global client_custom
207
+ if client_custom is None:
208
+ custom_client(host, port, username, password)
209
+
210
+ payload = {
211
+ "command": "set_led_intensity",
212
+ "experiment": experiment,
213
+ "reactor": pioreactor,
214
+ "led": "B",
215
+ "brightness": led2
216
+ }
217
+ client_custom.publish(f"pioreactor/control", json.dumps(payload))
218
+
219
+ def led3fn(led3, host, port, username, password, pioreactor, experiment):
220
+ global client_custom
221
+ if client_custom is None:
222
+ custom_client(host, port, username, password)
223
+
224
+ payload = {
225
+ "command": "set_led_intensity",
226
+ "experiment": experiment,
227
+ "reactor": pioreactor,
228
+ "led": "C",
229
+ "brightness": led3
230
+ }
231
+ client_custom.publish(f"pioreactor/control", json.dumps(payload))
232
+
233
+ def led4fn(led4, host, port, username, password, pioreactor, experiment):
234
+ global client_custom
235
+ if client_custom is None:
236
+ custom_client(host, port, username, password)
237
+
238
+ payload = {
239
+ "command": "set_led_intensity",
240
+ "experiment": experiment,
241
+ "reactor": pioreactor,
242
+ "led": "D",
243
+ "brightness": led4
244
+ }
245
+ client_custom.publish(f"pioreactor/control", json.dumps(payload))
246
+
247
+ def add_media(media, host, port, username, password, pioreactor, experiment):
248
+ global client_custom
249
+ if client_custom is None:
250
+ custom_client(host, port, username, password)
251
+
252
+ payload = {
253
+ "command": "pump_add_media",
254
+ "experiment": experiment,
255
+ "reactor": pioreactor,
256
+ "volume": media
257
+ }
258
+ client_custom.publish(f"pioreactor/control", json.dumps(payload))
259
+
260
+ def remove_waste(waste, host, port, username, password, pioreactor, experiment):
261
+ global client_custom
262
+ if client_custom is None:
263
+ custom_client(host, port, username, password)
264
+
265
+ payload = {
266
+ "command": "pump_remove_media",
267
+ "experiment": experiment,
268
+ "reactor": pioreactor,
269
+ "volume": waste
270
+ }
271
+ client_custom.publish(f"pioreactor/control", json.dumps(payload))
272
+
273
+ def cycle_media(cycle, host, port, username, password, pioreactor, experiment):
274
+ global client_custom
275
+ if client_custom is None:
276
+ custom_client(host, port, username, password)
277
+
278
+ payload = {
279
+ "command": "circulate_media",
280
+ "experiment": experiment,
281
+ "reactor": pioreactor,
282
+ "duration": cycle
283
+ }
284
+ client_custom.publish(f"pioreactor/control", json.dumps(payload))
285
+
286
+ def void_client():
287
+ global client_custom
288
+ if client_custom is not None:
289
+ client_custom.disconnect()
290
+ client_custom = None
291
+
292
+ # Define the interface components
293
+ with gr.Blocks() as demo:
294
+ with gr.Tab("Default"):
295
+ experiment_input = gr.Textbox(label="Experiment", value="Ed")
296
+ experiment_input.input(fn=void_client)
297
+
298
+ with gr.Blocks():
299
+ gr.Markdown("# Stirring")
300
+ rpm = gr.Slider(minimum=0, maximum=2000, step=50, label="RPM")
301
+
302
+ with gr.Row():
303
+ stir_state = gr.Radio(choices=["start", "stop", "update"], label="State")
304
+
305
+ st = gr.Button("Send Command")
306
+
307
+ st.click(
308
+ fn=stirring,
309
+ inputs=[rpm, HOST_gr, PORT_gr, USERNAME_gr, PASSWORD_gr, PIOREACTOR_gr, experiment_input, stir_state]
310
+ )
311
+
312
+ with gr.Blocks():
313
+ gr.Markdown("# Temperature Automation")
314
+
315
+ # Dropdown for selecting automation type
316
+ temp_option = gr.Dropdown(
317
+ choices=["Record Temp Only", "Heat To Temp"],
318
+ label="Temperature Automation",
319
+ value="Record Temp Only"
320
+ )
321
+
322
+ # Slider for temperature (initially hidden)
323
+ temperature_slider = gr.Slider(minimum=0, maximum=60, step=1, label="Temperature", visible=False)
324
+
325
+ # Button to start automation
326
+ with gr.Row():
327
+ temp_state = gr.Radio(choices=["start", "stop", "update", "restart"], label="State")
328
+ temp = gr.Button("Send Command")
329
+
330
+ # Update visibility of the slider based on dropdown selection
331
+ temp_option.change(
332
+ fn=toggle_temperature_input,
333
+ inputs=temp_option,
334
+ outputs=temperature_slider
335
+ )
336
+
337
+ temp.click(
338
+ fn=temp_automation,
339
+ inputs=[temperature_slider, HOST_gr, PORT_gr, USERNAME_gr, PASSWORD_gr, PIOREACTOR_gr, experiment_input, temp_state, temp_option]
340
+ )
341
+
342
+
343
+
344
+ with gr.Tab("Custom"):
345
+ # Input components
346
+ with gr.Row():
347
+ host_input = gr.Textbox(label="Host")
348
+ port_input = gr.Number(label="Port")
349
+
350
+ host_input.input(fn=void_client)
351
+ port_input.input(fn=void_client)
352
+
353
+ with gr.Row():
354
+ username_input = gr.Textbox(label="Username")
355
+ password_input = gr.Textbox(label="Password")
356
+ pioreactor_input = gr.Textbox(label="Pioreactor")
357
+ experiment_input = gr.Textbox(label="Experiment")
358
+
359
+ username_input.input(fn=void_client)
360
+ password_input.input(fn=void_client)
361
+ pioreactor_input.input(fn=void_client)
362
+ experiment_input.input(fn=void_client)
363
+
364
+ with gr.Blocks():
365
+ gr.Markdown("# Stirring")
366
+ rpm_input = gr.Slider(minimum=0, maximum=2000, step=50, label="RPM")
367
+
368
+ with gr.Row():
369
+ stir_state = gr.Radio(choices=["start", "stop", "update"], label="State")
370
+
371
+ st = gr.Button("Send Command")
372
+
373
+ st.click(
374
+ fn=stirring,
375
+ inputs=[rpm_input, host_input, port_input, username_input, password_input, pioreactor_input, experiment_input, stir_state]
376
+ )
377
+
378
+ with gr.Blocks():
379
+ gr.Markdown("# Temperature Automation")
380
+
381
+ # Dropdown for selecting automation type
382
+ temp_option = gr.Dropdown(
383
+ choices=["Record Temp Only", "Heat To Temp"],
384
+ label="Temperature Automation",
385
+ value="Record Temp Only"
386
+ )
387
+
388
+ # Slider for temperature (initially hidden)
389
+ temperature_slider = gr.Slider(minimum=0, maximum=60, step=1, label="Temperature", visible=False)
390
+
391
+ # Button to start automation
392
+ with gr.Row():
393
+ temp_state = gr.Radio(choices=["start", "stop", "update", "restart"], label="State")
394
+ temp = gr.Button("Send Command")
395
+
396
+ # Update visibility of the slider based on dropdown selection
397
+ temp_option.change(
398
+ fn=toggle_temperature_input,
399
+ inputs=temp_option,
400
+ outputs=temperature_slider
401
+ )
402
+
403
+ temp.click(
404
+ fn=temp_automation,
405
+ inputs=[temperature_slider, host_input, port_input, username_input, password_input, pioreactor_input, experiment_input, temp_state, temp_option]
406
+ )
407
+
408
+ with gr.Blocks():
409
+ with gr.Row():
410
+ with gr.Column():
411
+ gr.Markdown("# OD Reading")
412
+ od_state = gr.Radio(choices=["start", "stop"], label="State")
413
+ od_button = gr.Button("Send Command")
414
+
415
+ od_button.click(
416
+ fn=od,
417
+ inputs=[host_input, port_input, username_input, password_input, pioreactor_input, experiment_input, od_state]
418
+ )
419
+
420
+ with gr.Column():
421
+ gr.Markdown("# Growth Rate")
422
+ gr_state = gr.Radio(choices=["start", "stop"], label="State")
423
+ gr_button = gr.Button("Send Command")
424
+
425
+ gr_button.click(
426
+ fn=grf,
427
+ inputs=[host_input, port_input, username_input, password_input, pioreactor_input, experiment_input, gr_state]
428
+ )
429
+
430
+ with gr.Blocks():
431
+ gr.Markdown("# LEDS")
432
+
433
+ with gr.Row(): # Row for all channels
434
+ with gr.Column():
435
+ gr.Markdown("### Channel A")
436
+ led1 = gr.Slider(minimum=0, maximum=100, step=1, label="Intensity")
437
+ led1_button = gr.Button("Send Command")
438
+
439
+ led1_button.click(
440
+ fn=led1fn,
441
+ inputs=[led1, host_input, port_input, username_input, password_input, pioreactor_input, experiment_input]
442
+ )
443
+
444
+ with gr.Column():
445
+ gr.Markdown("### Channel B")
446
+ led2 = gr.Slider(minimum=0, maximum=100, step=1, label="Intensity")
447
+ led2_button = gr.Button("Send Command")
448
+
449
+ led2_button.click(
450
+ fn=led2fn,
451
+ inputs=[led2, host_input, port_input, username_input, password_input, pioreactor_input, experiment_input]
452
+ )
453
+
454
+ with gr.Column():
455
+ gr.Markdown("### Channel C")
456
+ led3 = gr.Slider(minimum=0, maximum=100, step=1, label="Intensity")
457
+ led3_button = gr.Button("Send Command")
458
+
459
+ led3_button.click(
460
+ fn=led3fn,
461
+ inputs=[led3, host_input, port_input, username_input, password_input, pioreactor_input, experiment_input]
462
+ )
463
+
464
+ with gr.Column():
465
+ gr.Markdown("### Channel D")
466
+ led4 = gr.Slider(minimum=0, maximum=100, step=1, label="Intensity")
467
+ led4_button = gr.Button("Send Command")
468
+
469
+ led4_button.click(
470
+ fn=led4fn,
471
+ inputs=[led4, host_input, port_input, username_input, password_input, pioreactor_input, experiment_input]
472
+ )
473
+
474
+ with gr.Blocks():
475
+ gr.Markdown("# Dosing")
476
+
477
+ with gr.Row():
478
+ with gr.Column():
479
+ gr.Markdown("### Add Media")
480
+
481
+ add_media_ml = gr.Number(label="Media (mL)", step=1, minimum=0, maximum=14)
482
+ add_media_button = gr.Button("Send Command")
483
+
484
+ add_media_button.click(
485
+ fn=add_media,
486
+ inputs=[add_media_ml, host_input, port_input, username_input, password_input, pioreactor_input, experiment_input]
487
+ )
488
+
489
+ with gr.Column():
490
+ gr.Markdown("### Remove Waste")
491
+
492
+ remove_waste_ml = gr.Number(label="Waste (mL)", step=1, minimum=0, maximum=20)
493
+ remove_waste_button = gr.Button("Send Command")
494
+
495
+ remove_waste_button.click(
496
+ fn=remove_waste,
497
+ inputs=[remove_waste_ml, host_input, port_input, username_input, password_input, pioreactor_input, experiment_input]
498
+ )
499
+
500
+ with gr.Column():
501
+ gr.Markdown("### Cycle Media")
502
+
503
+ cycle_media_sec = gr.Number(label="Cycle (s)", step=1, minimum=0, maximum=60)
504
+ cycle_media_button = gr.Button("Send Command")
505
+
506
+ cycle_media_button.click(
507
+ fn=cycle_media,
508
+ inputs=[cycle_media_sec, host_input, port_input, username_input, password_input, pioreactor_input, experiment_input]
509
+ )
510
+
511
+
512
+
513
+ # Launch the interface
514
+ demo.launch()