Skip to content

Commit 390e69c

Browse files
fixed multi-session logs recording and added status logging to TUI
1 parent 1e0b450 commit 390e69c

File tree

4 files changed

+43
-12
lines changed

4 files changed

+43
-12
lines changed

src/glassesRecord/OffsetLogger.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def __init__(self, device_ips: List, log_dir: str = "", log_interval: int = 10):
2727
log_interval (int, optional): Time in seconds between logging offsets. Default is 10 seconds.
2828
"""
2929

30-
os.makedirs("logs", exist_ok=True)
30+
os.makedirs(log_dir, exist_ok=True)
3131
self.log_file = os.path.join(log_dir, f"{datetime.now().strftime('%y%m%dT%H%M%S')}_offsets.csv")
3232
print(os.path.abspath(self.log_file))
3333
self.log_interval = log_interval

src/glassesRecord/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ The following parameters can be set in config.json to configure your recording s
7878
- `"path"`: Directory where log files will be stored.
7979
- `"level"`: Logging verbosity (e.g., `"INFO"`, `"DEBUG"`).
8080
- `"interval"`: Time interval (in seconds) for periodic logging or updates.
81+
- `"TUI_messages_len"`: The maximum number of recent logs displayed in the TUI. Only the last `TUI_messages_len` messages will be shown at any time.
8182

8283
- The `"single_session_mode"` option controls whether the recording session will involve a single recording start (and stop) for all releavant devices (`true`) OR it requires multiple concurrent recording starts with different batches of devices (`false`).
8384

src/glassesRecord/config.json

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,25 @@
11
{
22

3-
"network_id": "192.168.2",
3+
"network_id": "",
44
"host_id": {
55
"start": 101,
66
"end": 130
77
},
88
"ip_list": [
9-
"192.168.2.105",
10-
"192.168.2.110",
9+
"192.168.50.191",
10+
"192.168.50.130",
1111
"192.168.2.124",
1212
"192.168.2.016"
1313
],
1414
"logs": {
1515
"path": "logs/",
1616
"level": "INFO",
17-
"interval": 10
17+
"interval": 10,
18+
"TUI_messages_len": 3
1819
},
1920
"update_times": {
2021
"batch1": 3,
2122
"batch2": 5
2223
},
23-
"single_session_mode": true
24+
"single_session_mode": false
2425
}

src/glassesRecord/main.py

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88
from textual import work
99
from textual.app import App, ComposeResult
1010
from textual.binding import Binding
11-
from textual.widgets import Footer, Input
11+
from textual.widgets import Footer, Input, Label
1212
from rich.text import Text
13+
from asyncio import sleep
1314
import numbers
1415
from adb_wrapper import AdbWrapper
1516
import threading
@@ -44,6 +45,9 @@ class TableApp(App):
4445
session_dir = os.path.join(config["logs"]["path"], session_id)
4546
events_file = os.path.join(session_dir, "events.json")
4647
single_session_mode = config["single_session_mode"]
48+
status_widget = None
49+
status_messages = [f" glassesRecord TUI started in {"single-session mode" if single_session_mode else "multi-session mode"}; Session ID: {session_id}"]
50+
status_len = config["logs"]["TUI_messages_len"] # Number of status messages to keep
4751

4852
restart_app_in_progress = False
4953

@@ -68,6 +72,7 @@ def on_mount(self) -> None:
6872
format='[%(asctime)s] %(levelname)s [%(name)s] %(message)s')
6973
logging.getLogger('pupil_labs.realtime_api.time_echo').setLevel(logging.ERROR)
7074
self.logger = logging.getLogger('glassesRecord_TUI')
75+
self.status_widget = self.query_one(Label)
7176

7277
# Setup app theme and table
7378
self.theme = "textual-dark"
@@ -560,6 +565,18 @@ def stop_recording_offsets(self, device_list):
560565
print(e)
561566
pass
562567

568+
def update_status_widget(self, new_msg):
569+
"""Update the status widget with the provided message.
570+
571+
Args:
572+
message (str): The message to display in the status widget.
573+
"""
574+
self.status_messages.append(new_msg)
575+
self.status_messages = self.status_messages[-self.status_len:]
576+
577+
if self.status_widget:
578+
self.status_widget.update('\n'.join(self.status_messages))
579+
563580
#Defining actions
564581
@work(exclusive=True, thread=True)
565582
async def action_recording_start(self) -> None:
@@ -571,7 +588,8 @@ async def action_recording_start(self) -> None:
571588
table = self.query_one(SelectableRowsDataTable)
572589
selected_devices = [row.data[1] for row in table.selected_rows]
573590
self.logger.info("Selected devices ({}): {}".format(len(selected_devices), selected_devices))
574-
print("STARTING REC on selected devices")
591+
self.update_status_widget(f" Starting recording on {len(selected_devices)} device(s)...")
592+
# print("STARTING REC on selected devices")
575593

576594
if self.single_session_mode:
577595
if not self.offset_logger:
@@ -589,6 +607,8 @@ async def action_recording_start(self) -> None:
589607
for d in selected_devices:
590608
t = threading.Thread(target=self.start_recording, args=(d,), daemon=True)
591609
t.start()
610+
611+
self.update_status_widget(f" Start recordings action completed!")
592612

593613

594614
## Implementing action keys below to control the execution of certain operations manually by the operator.
@@ -602,13 +622,15 @@ async def action_recording_stop_and_save(self) -> None:
602622
"""
603623
table = self.query_one(SelectableRowsDataTable)
604624
selected_devices = [row.data[1] for row in table.selected_rows]
605-
print("STOPPING REC on selected device(s): ", selected_devices)
625+
self.update_status_widget(f" Saving recording on {len(selected_devices)} device(s)...")
626+
# print("STOPPING REC on selected device(s): ", selected_devices)
606627
self.logger.info(f"Stopping recording on {len(selected_devices)} device(s): {selected_devices}")
607628
# Stop offset logging if it was started
608629
self.stop_recording_offsets(selected_devices)
609630
for d in selected_devices:
610631
t = threading.Thread(target=self.stop_and_save_recording, args=(d,), daemon=True)
611632
t.start()
633+
self.update_status_widget(f" Save recordings action completed!")
612634

613635
@work(exclusive=True, thread=True)
614636
async def action_recording_stop_and_discard(self) -> None:
@@ -619,13 +641,15 @@ async def action_recording_stop_and_discard(self) -> None:
619641
"""
620642
table = self.query_one(SelectableRowsDataTable)
621643
selected_devices = [row.data[1] for row in table.selected_rows]
622-
print("DISCARDING REC on selected devices")
644+
self.update_status_widget(f" Discarding recordings on {len(selected_devices)} device(s)...")
645+
# print("DISCARDING REC on selected devices")
623646
# Stop offset logging if it was started
624-
self.stop_recording_offsets(selected_devices)
625647
self.logger.info(f"Discarding recording on {len(selected_devices)} device(s): {selected_devices}")
648+
self.stop_recording_offsets(selected_devices)
626649
for d in selected_devices:
627650
t = threading.Thread(target=self.stop_and_discard_recording, args=(d,), daemon=True)
628651
t.start()
652+
self.update_status_widget(f" Discard recordings action completed!")
629653

630654
@work(exclusive=True, thread=True)
631655
async def action_restart_app_on_devices(self) -> None:
@@ -645,6 +669,7 @@ async def action_restart_app_on_devices(self) -> None:
645669

646670
table = self.query_one(SelectableRowsDataTable)
647671
selected_device_ip_addrs = [row.data[1] for row in table.selected_rows]
672+
self.update_status_widget(f" Restarting app on {len(selected_device_ip_addrs)} devices...")
648673
self.logger.info("Selected devices ({}): {}".format(len(selected_device_ip_addrs), selected_device_ip_addrs))
649674

650675
def f(ip_addr):
@@ -663,6 +688,7 @@ def f(ip_addr):
663688
for t in tasks:
664689
t.join()
665690
self.logger.info(f'Restarting apps has finished!')
691+
self.update_status_widget(f" App restart action completed!")
666692
finally:
667693
self.restart_app_in_progress = False
668694
self.logger.info(f'self.restart_app_in_progress = False')
@@ -676,6 +702,7 @@ async def action_reconnect_adb(self) -> None:
676702
print("RESTARTING ADB on selected devices!")
677703
table = self.query_one(SelectableRowsDataTable)
678704
selected_device_ip_addrs = [row.data[1] for row in table.selected_rows]
705+
self.update_status_widget(f" Restarting adb on {len(selected_device_ip_addrs)} devices...")
679706
self.logger.info("Selected devices ({}): {}".format(len(selected_device_ip_addrs), selected_device_ip_addrs))
680707

681708
def run_adb_cmd(ip_addr):
@@ -689,6 +716,7 @@ def run_adb_cmd(ip_addr):
689716
t.start()
690717

691718
print('FINISHED dispatching adb restart threads!')
719+
self.update_status_widget(f" adb restart action completed!")
692720

693721
@work(exclusive=True, thread=True)
694722
def action_stop_all_offsets(self) -> None:
@@ -711,7 +739,7 @@ def action_toggle_dark(self) -> None:
711739
description="Save Recording"),
712740
Binding(key="u", action="recording_stop_and_discard",
713741
description="Cancel Recording"),
714-
Binding(key="o", action="stop_all_offsets", description="Stop offsets logging on all devices"),
742+
*([Binding(key="o", action="stop_all_offsets", description="Stop offsets logging on all devices")] if config["single_session_mode"] else []),
715743
Binding(key="t", action="restart_app_on_devices", description="Restart App"),
716744
Binding(key="a", action="reconnect_adb", description="Reconnect adb"),
717745
Binding(key="d", action="toggle_dark", description="Toggle dark mode"),
@@ -725,6 +753,7 @@ def compose(self) -> ComposeResult:
725753
"""
726754
yield SelectableRowsDataTable()
727755
yield Input(id = "event_tag", placeholder="Enter event tag/desc. here and press enter to log the event.", tooltip = "Use Tab to change focus")
756+
yield Label(self.status_messages[0])
728757
yield Footer(id = "footer")
729758

730759
def as_colored_text(val, **kwargs):

0 commit comments

Comments
 (0)