|
68 | 68 | "try:\n", |
69 | 69 | " client = RioClient(base_url=API_BASE_URL)\n", |
70 | 70 | " health = client.health()\n", |
71 | | - " print(f\"\u2705 Connected to Rio API at {API_BASE_URL}\")\n", |
| 71 | + " print(f\"✅ Connected to Rio API at {API_BASE_URL}\")\n", |
72 | 72 | " print(f\" Status: {health['status']}, Simulation: {health['simulation']}\")\n", |
73 | 73 | "except Exception as e:\n", |
74 | | - " print(f\"\u274c Failed to connect to API: {e}\")\n", |
| 74 | + " print(f\"❌ Failed to connect to API: {e}\")\n", |
75 | 75 | " print(f\" Make sure the API server is running at {API_BASE_URL}\")\n", |
76 | 76 | " raise\n", |
77 | 77 | "\n", |
78 | 78 | "# Initialize pump API (lazy connection)\n", |
79 | 79 | "try:\n", |
80 | 80 | " pump_api = SyringePumpAPI(base_url=PUMP_API_URL)\n", |
81 | | - " print(f\"\u2705 Pump API configured at {PUMP_API_URL}\")\n", |
| 81 | + " print(f\"✅ Pump API configured at {PUMP_API_URL}\")\n", |
82 | 82 | "except Exception as e:\n", |
83 | 83 | " pump_api = None\n", |
84 | | - " print(f\"\u26a0\ufe0f Pump API unavailable: {e}\")\n" |
| 84 | + " print(f\"⚠️ Pump API unavailable: {e}\")\n" |
85 | 85 | ] |
86 | 86 | }, |
87 | 87 | { |
|
134 | 134 | " except Exception as e:\n", |
135 | 135 | " with flow_status:\n", |
136 | 136 | " clear_output()\n", |
137 | | - " print(f\"\u274c Error: {e}\")\n", |
| 137 | + " print(f\"❌ Error: {e}\")\n", |
138 | 138 | " \n", |
139 | 139 | " def create_flow_handler(param_name, setter_func):\n", |
140 | 140 | " \"\"\"Create parameter handler for flow/pressure (like internship pattern)\"\"\"\n", |
|
146 | 146 | " getattr(client, setter_func)(channel, value)\n", |
147 | 147 | " with flow_status:\n", |
148 | 148 | " clear_output()\n", |
149 | | - " print(f\"\u2705 Updated {param_name} for channel {channel} to {value}\")\n", |
| 149 | + " print(f\"✅ Updated {param_name} for channel {channel} to {value}\")\n", |
150 | 150 | " update_flow_state()\n", |
151 | 151 | " except Exception as e:\n", |
152 | 152 | " with flow_status:\n", |
153 | 153 | " clear_output()\n", |
154 | | - " print(f\"\u274c Error updating {param_name}: {e}\")\n", |
| 154 | + " print(f\"❌ Error updating {param_name}: {e}\")\n", |
155 | 155 | " return handler\n", |
156 | 156 | " \n", |
157 | 157 | " def on_channel_select(change):\n", |
|
165 | 165 | " update_flow_state()\n", |
166 | 166 | " except Exception as e:\n", |
167 | 167 | " with flow_status:\n", |
168 | | - " print(f\"\u274c Error loading channel {change['new']}: {e}\")\n", |
| 168 | + " print(f\"❌ Error loading channel {change['new']}: {e}\")\n", |
169 | 169 | " \n", |
170 | 170 | " flow_channel.observe(on_channel_select, names='value')\n", |
171 | 171 | " flow_rate.observe(create_flow_handler('flow', 'set_flow'), 'value')\n", |
|
180 | 180 | " \n", |
181 | 181 | " flow_status_box = widgets.VBox([\n", |
182 | 182 | " widgets.HTML(\"<h3>Status</h3>\"),\n", |
183 | | - " widgets.Button(description='\ud83d\udd04 Refresh', button_style='info'),\n", |
| 183 | + " widgets.Button(description='🔄 Refresh', button_style='info'),\n", |
184 | 184 | " flow_status\n", |
185 | 185 | " ], layout=widgets.Layout(min_width='350px', margin='0 0 0 20px'))\n", |
186 | 186 | " \n", |
|
190 | 190 | " # ===== HEATER TAB =====\n", |
191 | 191 | " # Use Dropdown for heater selection\n", |
192 | 192 | " heater_select = widgets.Dropdown(options=[0, 1, 2, 3], value=0, description='Heater:', style={'description_width': 'initial'})\n", |
193 | | - " heater_temp = widgets.FloatSlider(value=25, min=0, max=100, step=0.1, description='Temp (\u00b0C):', style={'description_width': 'initial'})\n", |
| 193 | + " heater_temp = widgets.FloatSlider(value=25, min=0, max=100, step=0.1, description='Temp (°C):', style={'description_width': 'initial'})\n", |
194 | 194 | " heater_pid = widgets.ToggleButton(value=False, description='PID Control', button_style='info')\n", |
195 | 195 | " heater_stir = widgets.ToggleButton(value=False, description='Stirrer', button_style='info')\n", |
196 | 196 | " heater_status = widgets.Output(layout=widgets.Layout(\n", |
|
211 | 211 | " print(\"Current Heater States:\")\n", |
212 | 212 | " for i, h in enumerate(state['heaters']):\n", |
213 | 213 | " print(f\"\\n Heater {i}:\")\n", |
214 | | - " print(f\" Temp: {h['temp_c_actual']:.1f}\u00b0C (target: {h['temp_c_target']:.1f}\u00b0C)\")\n", |
| 214 | + " print(f\" Temp: {h['temp_c_actual']:.1f}°C (target: {h['temp_c_target']:.1f}°C)\")\n", |
215 | 215 | " print(f\" PID: {'ON' if h['pid_enabled'] else 'OFF'}\")\n", |
216 | 216 | " print(f\" Stir: {'ON' if h['stir_enabled'] else 'OFF'}\")\n", |
217 | 217 | " print(f\" Status: {h['status_text']}\")\n", |
218 | 218 | " except Exception as e:\n", |
219 | 219 | " with heater_status:\n", |
220 | 220 | " clear_output()\n", |
221 | | - " print(f\"\u274c Error: {e}\")\n", |
| 221 | + " print(f\"❌ Error: {e}\")\n", |
222 | 222 | " \n", |
223 | 223 | " def create_heater_handler(param_name, setter_func):\n", |
224 | 224 | " \"\"\"Create parameter handler for heater controls\"\"\"\n", |
|
230 | 230 | " getattr(client, setter_func)(heater, value)\n", |
231 | 231 | " with heater_status:\n", |
232 | 232 | " clear_output()\n", |
233 | | - " print(f\"\u2705 Updated {param_name} for heater {heater} to {value}\")\n", |
| 233 | + " print(f\"✅ Updated {param_name} for heater {heater} to {value}\")\n", |
234 | 234 | " update_heater_state()\n", |
235 | 235 | " except Exception as e:\n", |
236 | 236 | " with heater_status:\n", |
237 | 237 | " clear_output()\n", |
238 | | - " print(f\"\u274c Error updating {param_name}: {e}\")\n", |
| 238 | + " print(f\"❌ Error updating {param_name}: {e}\")\n", |
239 | 239 | " return handler\n", |
240 | 240 | " \n", |
241 | 241 | " def on_heater_select(change):\n", |
|
251 | 251 | " update_heater_state()\n", |
252 | 252 | " except Exception as e:\n", |
253 | 253 | " with heater_status:\n", |
254 | | - " print(f\"\u274c Error loading heater {change['new']}: {e}\")\n", |
| 254 | + " print(f\"❌ Error loading heater {change['new']}: {e}\")\n", |
255 | 255 | " \n", |
256 | 256 | " heater_select.observe(on_heater_select, names='value')\n", |
257 | 257 | " heater_temp.observe(create_heater_handler('temperature', 'set_heater_temp'), 'value')\n", |
|
267 | 267 | " \n", |
268 | 268 | " heater_status_box = widgets.VBox([\n", |
269 | 269 | " widgets.HTML(\"<h3>Status</h3>\"),\n", |
270 | | - " widgets.Button(description='\ud83d\udd04 Refresh', button_style='info'),\n", |
| 270 | + " widgets.Button(description='🔄 Refresh', button_style='info'),\n", |
271 | 271 | " heater_status\n", |
272 | 272 | " ], layout=widgets.Layout(min_width='350px', margin='0 0 0 20px'))\n", |
273 | 273 | " \n", |
274 | 274 | " heater_tab = widgets.HBox([heater_basic, heater_status_box])\n", |
275 | 275 | " heater_tab.children[1].children[1].on_click(lambda b: update_heater_state())\n", |
276 | 276 | " \n", |
277 | 277 | " # ===== CAMERA/STROBE TAB =====\n", |
278 | | - " stream_btn = widgets.ToggleButton(value=False, description='\u25b6 Start Camera', button_style='success')\n", |
279 | | - " capture_btn = widgets.Button(description='\ud83d\udcf8 Capture Image', button_style='success')\n", |
| 278 | + " stream_btn = widgets.ToggleButton(value=False, description='▶ Start Camera', button_style='success')\n", |
| 279 | + " capture_btn = widgets.Button(description='📸 Capture Image', button_style='success')\n", |
280 | 280 | " save_container = widgets.Output()\n", |
281 | | - " enable_btn = widgets.ToggleButton(value=False, description='\u23fb Enable Strobe', button_style='success')\n", |
282 | | - " period = widgets.FloatSlider(min=1, max=10000, step=1, value=50, description='Period (\u00b5s):', style={'description_width': 'initial'})\n", |
283 | | - " width = widgets.FloatSlider(min=0.1, max=1000, step=0.1, value=0.1, description='Width (\u00b5s):', style={'description_width': 'initial'})\n", |
284 | | - " hold_btn = widgets.ToggleButton(value=False, description='\ud83d\udd06 Hold Mode')\n", |
| 281 | + " enable_btn = widgets.ToggleButton(value=False, description='⏻ Enable Strobe', button_style='success')\n", |
| 282 | + " period = widgets.FloatSlider(min=1, max=10000, step=1, value=50, description='Period (µs):', style={'description_width': 'initial'})\n", |
| 283 | + " width = widgets.FloatSlider(min=0.1, max=1000, step=0.1, value=0.1, description='Width (µs):', style={'description_width': 'initial'})\n", |
| 284 | + " hold_btn = widgets.ToggleButton(value=False, description='🔆 Hold Mode')\n", |
285 | 285 | " stream_container = widgets.Output(layout=widgets.Layout(width='400px', height='300px'))\n", |
286 | 286 | " captured_container = widgets.Output(layout=widgets.Layout(width='400px', height='300px'))\n", |
287 | 287 | " \n", |
288 | 288 | " def toggle_stream(change):\n", |
289 | 289 | " if change['name'] == 'value':\n", |
290 | 290 | " if change['new']:\n", |
291 | | - " stream_btn.description = '\u23f9 Stop Camera'\n", |
| 291 | + " stream_btn.description = '⏹ Stop Camera'\n", |
292 | 292 | " stream_btn.button_style = 'danger'\n", |
293 | 293 | " with stream_container:\n", |
294 | 294 | " clear_output()\n", |
295 | 295 | " # Note: MJPEG stream endpoint would go here if available\n", |
296 | 296 | " display(HTML('<div style=\"width:400px; height:300px; border:2px solid #4CAF50; border-radius:4px; display:flex; align-items:center; justify-content:center;\">Camera Stream (MJPEG endpoint not yet available)</div>'))\n", |
297 | 297 | " else:\n", |
298 | | - " stream_btn.description = '\u25b6 Start Camera'\n", |
| 298 | + " stream_btn.description = '▶ Start Camera'\n", |
299 | 299 | " stream_btn.button_style = 'success'\n", |
300 | 300 | " with stream_container:\n", |
301 | 301 | " clear_output()\n", |
|
316 | 316 | " download=\"capture_{timestamp}.jpg\"\n", |
317 | 317 | " style=\"padding: 6px 12px; background-color: #4CAF50; color: white; \n", |
318 | 318 | " text-decoration: none; border-radius: 4px; display: inline-block;\">\n", |
319 | | - " \ud83d\udcbe Save Image\n", |
| 319 | + " 💾 Save Image\n", |
320 | 320 | " </a>\n", |
321 | 321 | " \"\"\"))\n", |
322 | 322 | " with status_output:\n", |
323 | | - " print(\"\u2705 Image captured! Click 'Save Image' to download.\")\n", |
| 323 | + " print(\"✅ Image captured! Click 'Save Image' to download.\")\n", |
324 | 324 | " else:\n", |
325 | 325 | " with status_output:\n", |
326 | | - " print(\"\u274c No image data received\")\n", |
| 326 | + " print(\"❌ No image data received\")\n", |
327 | 327 | " except Exception as e:\n", |
328 | 328 | " with status_output:\n", |
329 | | - " print(f\"\u274c Error capturing image: {e}\")\n", |
| 329 | + " print(f\"❌ Error capturing image: {e}\")\n", |
330 | 330 | " \n", |
331 | 331 | " def update_strobe(change=None):\n", |
332 | 332 | " try:\n", |
|
338 | 338 | " client.set_strobe_hold(hold_btn.value)\n", |
339 | 339 | " except Exception as e:\n", |
340 | 340 | " with status_output:\n", |
341 | | - " print(f\"\u274c Error updating strobe: {e}\")\n", |
| 341 | + " print(f\"❌ Error updating strobe: {e}\")\n", |
342 | 342 | " \n", |
343 | 343 | " def on_strobe_toggle(change):\n", |
344 | 344 | " if change['name'] == 'value':\n", |
345 | 345 | " if change['new']:\n", |
346 | | - " enable_btn.description = '\u23f9 Disable Strobe'\n", |
| 346 | + " enable_btn.description = '⏹ Disable Strobe'\n", |
347 | 347 | " enable_btn.button_style = 'danger'\n", |
348 | 348 | " else:\n", |
349 | | - " enable_btn.description = '\u23fb Enable Strobe'\n", |
| 349 | + " enable_btn.description = '⏻ Enable Strobe'\n", |
350 | 350 | " enable_btn.button_style = 'success'\n", |
351 | 351 | " update_strobe()\n", |
352 | 352 | " \n", |
|
408 | 408 | " )\n", |
409 | 409 | " pump_state = widgets.ToggleButton(\n", |
410 | 410 | " value=False,\n", |
411 | | - " description=\"\u25b6 Run\",\n", |
| 411 | + " description=\"▶ Run\",\n", |
412 | 412 | " button_style=\"success\",\n", |
413 | 413 | " )\n", |
414 | 414 | " pump_unit = widgets.Dropdown(\n", |
|
457 | 457 | " with pump_status:\n", |
458 | 458 | " clear_output()\n", |
459 | 459 | " if pump_api is None:\n", |
460 | | - " print(\"\u26a0\ufe0f Pump API not configured\")\n", |
| 460 | + " print(\"⚠️ Pump API not configured\")\n", |
461 | 461 | " return\n", |
462 | 462 | " try:\n", |
463 | 463 | " pump_refreshing[\"active\"] = True\n", |
|
473 | 473 | " pump_direction.value = \"infuse\" if int(state[\"direction\"]) >= 0 else \"withdraw\"\n", |
474 | 474 | " if state.get(\"state\") is not None:\n", |
475 | 475 | " pump_state.value = bool(state[\"state\"])\n", |
476 | | - " pump_state.description = \"\u23f9 Stop\" if pump_state.value else \"\u25b6 Run\"\n", |
| 476 | + " pump_state.description = \"⏹ Stop\" if pump_state.value else \"▶ Run\"\n", |
477 | 477 | " pump_state.button_style = \"danger\" if pump_state.value else \"success\"\n", |
478 | 478 | " if state.get(\"unit\"):\n", |
479 | 479 | " pump_unit.value = state[\"unit\"]\n", |
|
488 | 488 | " pump_enable.description = \"Enabled\" if pump_enable.value else \"Disabled\"\n", |
489 | 489 | " pump_enable.button_style = \"success\" if pump_enable.value else \"warning\"\n", |
490 | 490 | " except Exception as e:\n", |
491 | | - " print(f\"\u274c Pump state error: {e}\")\n", |
| 491 | + " print(f\"❌ Pump state error: {e}\")\n", |
492 | 492 | " finally:\n", |
493 | 493 | " pump_refreshing[\"active\"] = False\n", |
494 | 494 | "\n", |
|
503 | 503 | " except Exception as e:\n", |
504 | 504 | " with pump_status:\n", |
505 | 505 | " clear_output()\n", |
506 | | - " print(f\"\u274c Failed to set flow: {e}\")\n", |
| 506 | + " print(f\"❌ Failed to set flow: {e}\")\n", |
507 | 507 | "\n", |
508 | 508 | " def on_pump_diameter(change):\n", |
509 | 509 | " if change[\"name\"] != \"value\" or pump_refreshing[\"active\"]:\n", |
|
516 | 516 | " except Exception as e:\n", |
517 | 517 | " with pump_status:\n", |
518 | 518 | " clear_output()\n", |
519 | | - " print(f\"\u274c Failed to set diameter: {e}\")\n", |
| 519 | + " print(f\"❌ Failed to set diameter: {e}\")\n", |
520 | 520 | "\n", |
521 | 521 | " def on_pump_direction(change):\n", |
522 | 522 | " if change[\"name\"] != \"value\" or pump_refreshing[\"active\"]:\n", |
|
529 | 529 | " except Exception as e:\n", |
530 | 530 | " with pump_status:\n", |
531 | 531 | " clear_output()\n", |
532 | | - " print(f\"\u274c Failed to set direction: {e}\")\n", |
| 532 | + " print(f\"❌ Failed to set direction: {e}\")\n", |
533 | 533 | "\n", |
534 | 534 | " def on_pump_state(change):\n", |
535 | 535 | " if change[\"name\"] != \"value\" or pump_refreshing[\"active\"]:\n", |
536 | 536 | " return\n", |
537 | | - " pump_state.description = \"\u23f9 Stop\" if change[\"new\"] else \"\u25b6 Run\"\n", |
| 537 | + " pump_state.description = \"⏹ Stop\" if change[\"new\"] else \"▶ Run\"\n", |
538 | 538 | " pump_state.button_style = \"danger\" if change[\"new\"] else \"success\"\n", |
539 | 539 | " if pump_api is None:\n", |
540 | 540 | " return\n", |
|
544 | 544 | " except Exception as e:\n", |
545 | 545 | " with pump_status:\n", |
546 | 546 | " clear_output()\n", |
547 | | - " print(f\"\u274c Failed to set state: {e}\")\n", |
| 547 | + " print(f\"❌ Failed to set state: {e}\")\n", |
548 | 548 | "\n", |
549 | 549 | " def on_pump_unit(change):\n", |
550 | 550 | " if change[\"name\"] != \"value\" or pump_refreshing[\"active\"]:\n", |
|
557 | 557 | " except Exception as e:\n", |
558 | 558 | " with pump_status:\n", |
559 | 559 | " clear_output()\n", |
560 | | - " print(f\"\u274c Failed to set unit: {e}\")\n", |
| 560 | + " print(f\"❌ Failed to set unit: {e}\")\n", |
561 | 561 | "\n", |
562 | 562 | " def on_pump_gearbox(change):\n", |
563 | 563 | " if change[\"name\"] != \"value\" or pump_refreshing[\"active\"]:\n", |
|
570 | 570 | " except Exception as e:\n", |
571 | 571 | " with pump_status:\n", |
572 | 572 | " clear_output()\n", |
573 | | - " print(f\"\u274c Failed to set gearbox: {e}\")\n", |
| 573 | + " print(f\"❌ Failed to set gearbox: {e}\")\n", |
574 | 574 | "\n", |
575 | 575 | " def on_pump_microstep(change):\n", |
576 | 576 | " if change[\"name\"] != \"value\" or pump_refreshing[\"active\"]:\n", |
|
583 | 583 | " except Exception as e:\n", |
584 | 584 | " with pump_status:\n", |
585 | 585 | " clear_output()\n", |
586 | | - " print(f\"\u274c Failed to set microstep: {e}\")\n", |
| 586 | + " print(f\"❌ Failed to set microstep: {e}\")\n", |
587 | 587 | "\n", |
588 | 588 | " def on_pump_threadrod(change):\n", |
589 | 589 | " if change[\"name\"] != \"value\" or pump_refreshing[\"active\"]:\n", |
|
596 | 596 | " except Exception as e:\n", |
597 | 597 | " with pump_status:\n", |
598 | 598 | " clear_output()\n", |
599 | | - " print(f\"\u274c Failed to set thread rod: {e}\")\n", |
| 599 | + " print(f\"❌ Failed to set thread rod: {e}\")\n", |
600 | 600 | "\n", |
601 | 601 | " def on_pump_enable(change):\n", |
602 | 602 | " if change[\"name\"] != \"value\" or pump_refreshing[\"active\"]:\n", |
|
611 | 611 | " except Exception as e:\n", |
612 | 612 | " with pump_status:\n", |
613 | 613 | " clear_output()\n", |
614 | | - " print(f\"\u274c Failed to set enable: {e}\")\n", |
| 614 | + " print(f\"❌ Failed to set enable: {e}\")\n", |
615 | 615 | "\n", |
616 | 616 | " pump_select.observe(lambda change: refresh_pump_state(), names=\"value\")\n", |
617 | 617 | " pump_flow.observe(on_pump_flow, names=\"value\")\n", |
|
638 | 638 | " pump_microstep,\n", |
639 | 639 | " pump_threadrod,\n", |
640 | 640 | " pump_enable,\n", |
641 | | - " widgets.Button(description=\"\ud83d\udd04 Refresh\", button_style=\"info\"),\n", |
| 641 | + " widgets.Button(description=\"🔄 Refresh\", button_style=\"info\"),\n", |
642 | 642 | " ]\n", |
643 | 643 | " )\n", |
644 | 644 | " pump_controls.children[-1].on_click(lambda b: refresh_pump_state())\n", |
|
683 | 683 | " \n", |
684 | 684 | " with emergency_status:\n", |
685 | 685 | " clear_output()\n", |
686 | | - " print(\"\ud83d\uded1 EMERGENCY STOP: All operations stopped\")\n", |
| 686 | + " print(\"🛑 EMERGENCY STOP: All operations stopped\")\n", |
687 | 687 | " print(\" - All flow channels set to 0\")\n", |
688 | 688 | " print(\" - All heaters disabled\")\n", |
689 | 689 | " print(\" - Strobe disabled\")\n", |
690 | 690 | " except Exception as e:\n", |
691 | 691 | " with emergency_status:\n", |
692 | | - " print(f\"\u274c Emergency stop error: {e}\")\n", |
| 692 | + " print(f\"❌ Emergency stop error: {e}\")\n", |
693 | 693 | " \n", |
694 | 694 | " emergency_btn.on_click(emergency_stop)\n", |
695 | 695 | " \n", |
|
0 commit comments