From 819b9e634b18b9aaebb3cc92291927e33dd99589 Mon Sep 17 00:00:00 2001 From: Théo de la Hogue Date: Wed, 6 Apr 2022 15:11:08 +0200 Subject: Improving TobiiController management --- src/argaze/TobiiGlassesPro2/TobiiController.py | 153 ++++++++++++++----------- src/argaze/utils/README.md | 2 +- src/argaze/utils/calibrate_tobii_camera.py | 2 +- src/argaze/utils/live_tobii_aruco_detection.py | 2 +- src/argaze/utils/live_tobii_session.py | 2 +- src/argaze/utils/record_tobii_session.py | 30 ++--- 6 files changed, 107 insertions(+), 84 deletions(-) (limited to 'src') diff --git a/src/argaze/TobiiGlassesPro2/TobiiController.py b/src/argaze/TobiiGlassesPro2/TobiiController.py index 89dbc71..1f4e302 100644 --- a/src/argaze/TobiiGlassesPro2/TobiiController.py +++ b/src/argaze/TobiiGlassesPro2/TobiiController.py @@ -1,32 +1,47 @@ #!/usr/bin/env python import datetime +import uuid from argaze.TobiiGlassesPro2 import TobiiNetworkInterface, TobiiData, TobiiVideo TOBII_DATETIME_FORMAT = '%Y-%m-%dT%H:%M:%S+%f' TOBII_DATETIME_FORMAT_HUMREAD = '%d/%m/%Y %H:%M:%S' +DEFAULT_PROJECT_NAME = 'DefaultProject' +DEFAULT_PARTICIPANT_NAME = 'DefaultParticipant' +DEFAULT_RECORD_NAME = 'DefaultRecord' + class TobiiController(TobiiNetworkInterface.TobiiNetworkInterface): """Handle Tobii glasses Pro 2 device using network interface.""" project_name = None + """Project name.""" + + project_id = None """Project identifier.""" + participant_name = None + """Participant name.""" + participant_id = None """Participant identifier.""" calibration_id = None """Calibration identifier.""" - def __init__(self, ip_address, project_name, participant_id): + def __init__(self, ip_address, project_name = DEFAULT_PROJECT_NAME, participant_name = DEFAULT_PARTICIPANT_NAME): """Create a project, a participant and start calibration.""" super().__init__(ip_address) + # bind to project or create one if it doesn't exist self.project_name = project_name - self.project_id = self.create_project(self.project_name) - self.participant_id = self.create_participant(self.project_id, self.project_name) + self.project_id = self.set_project(self.project_name) + + # bind to participant or create one if it doesn't exist + self.participant_name = participant_name + self.participant_id = self.set_participant(self.project_id, self.participant_name) self.__recording_index = 0 @@ -38,29 +53,6 @@ class TobiiController(TobiiNetworkInterface.TobiiNetworkInterface): def __get_current_datetime(self, timeformat=TOBII_DATETIME_FORMAT): return datetime.datetime.now().replace(microsecond=0).strftime(timeformat) - def calibrate(self): - """Start Tobii glasses calibration""" - - input('Position Tobbi glasses calibration target then presse \'Enter\' to start calibration.') - - data = { - 'ca_project': self.project_id, - 'ca_type': 'default', - 'ca_participant': self.participant_id, - 'ca_created': self.__get_current_datetime() - } - - json_data = super().post_request('/api/calibrations', data) - - self.calibration_id = json_data['ca_id'] - - super().post_request('/api/calibrations/' + self.calibration_id + '/start') - - status = super().wait_for_status('/api/calibrations/' + self.calibration_id + '/status', 'ca_state', ['calibrating', 'calibrated', 'stale', 'uncalibrated', 'failed']) - - if status == 'uncalibrated' or status == 'stale' or status == 'failed': - raise Error(f'Tobii calibration {self.calibration_id} {status}') - # STREAMING FEATURES def enable_data_stream(self): @@ -97,35 +89,18 @@ class TobiiController(TobiiNetworkInterface.TobiiNetworkInterface): # PROJECT FEATURES - def get_projects(self): - return super().get_request('/api/projects') - - def get_project_id(self, project_name): - - project_id = None - projects = super().get_request('/api/projects') - - for project in projects: - - try: - if project['pr_info']['Name'] == project_name: - project_id = project['pr_id'] - except: - pass - - return project_id - - def create_project(self, projectname = 'DefaultProjectName'): + def set_project(self, project_name = DEFAULT_PROJECT_NAME): + """Bind to a project or create one if it doesn't exist.""" - project_id = self.get_project_id(projectname) + project_id = self.get_project_id(project_name) if project_id is None: data = { 'pr_info' : { 'CreationDate': self.__get_current_datetime(timeformat=TOBII_DATETIME_FORMAT_HUMREAD), - 'EagleId': str(uuid.uuid5(uuid.NAMESPACE_DNS, projectname)), - 'Name': projectname + 'EagleId': str(uuid.uuid5(uuid.NAMESPACE_DNS, project_name)), + 'Name': project_name }, 'pr_created': self.__get_current_datetime() } @@ -138,13 +113,31 @@ class TobiiController(TobiiNetworkInterface.TobiiNetworkInterface): return project_id + def get_project_id(self, project_name): + + project_id = None + projects = super().get_request('/api/projects') + + for project in projects: + + try: + if project['pr_info']['Name'] == project_name: + project_id = project['pr_id'] + except: + pass + + return project_id + + def get_projects(self): + return super().get_request('/api/projects') + # PARTICIPANT FEATURES - def create_participant(self, project_id, participant_name = 'DefaultUser', participant_notes = ''): + def set_participant(self, project_id, participant_name = DEFAULT_PARTICIPANT_NAME, participant_notes = ''): + """Bind to a participant or create one if it doesn't exist.""" participant_id = self.get_participant_id(participant_name) - self.participant_name = participant_name - + if participant_id is None: data = { @@ -184,12 +177,42 @@ class TobiiController(TobiiNetworkInterface.TobiiNetworkInterface): def get_participants(self): return super().get_request('/api/participants') + # CALIBRATION + + def calibrate(self): + """Start Tobii glasses calibration for current project and participant.""" + + input('Position Tobbi glasses calibration target then presse \'Enter\' to start calibration.') + + data = { + 'ca_project': self.project_id, + 'ca_type': 'default', + 'ca_participant': self.participant_id, + 'ca_created': self.__get_current_datetime() + } + + json_data = super().post_request('/api/calibrations', data) + + self.calibration_id = json_data['ca_id'] + + super().post_request('/api/calibrations/' + self.calibration_id + '/start') + + status = super().wait_for_status('/api/calibrations/' + self.calibration_id + '/status', 'ca_state', ['calibrating', 'calibrated', 'stale', 'uncalibrated', 'failed']) + + if status == 'uncalibrated' or status == 'stale' or status == 'failed': + raise Error(f'Tobii calibration {self.calibration_id} {status}') + # RECORDING FEATURES def __wait_for_recording_status(self, recording_id, status_array = ['init', 'starting', 'recording', 'pausing', 'paused', 'stopping', 'stopped', 'done', 'stale', 'failed']): return super().wait_for_status('/api/recordings/' + recording_id + '/status', 'rec_state', status_array) - def create_recording(self, participant_id, recording_notes = ''): + def create_recording(self, participant_name, recording_notes = ''): + + participant_id = self.get_participant_id(participant_name) + + if participant_id is None: + raise NameError(f'{participant_name} participant doesn\'t exist') self.__recording_index += 1 recording_name = f'Recording_{self.__recording_index}' @@ -197,44 +220,44 @@ class TobiiController(TobiiNetworkInterface.TobiiNetworkInterface): data = { 'rec_participant': participant_id, 'rec_info': { - 'EagleId': str(uuid.uuid5(uuid.NAMESPACE_DNS, self.participant_name)), + 'EagleId': str(uuid.uuid5(uuid.NAMESPACE_DNS, participant_name)), 'Name': recording_name, - 'Notes': recording_notes}, - 'rec_created': self.__get_current_datetime() - } + 'Notes': recording_notes + }, + 'rec_created': self.__get_current_datetime() + } json_data = super().post_request('/api/recordings', data) return json_data['rec_id'] def start_recording(self, recording_id): - """Enable recording on the Tobii interface's SD Card""" + """Start recording on the Tobii interface's SD Card.""" super().post_request('/api/recordings/' + recording_id + '/start') - if self.__wait_for_recording_status(recording_id, ['recording']) == 'recording': - return True - - return False + return self.__wait_for_recording_status(recording_id, ['recording']) == 'recording' def stop_recording(self, recording_id): - """Disable recording on the Tobii interface's SD Card""" + """Stop recording on the Tobii interface's SD Card.""" super().post_request('/api/recordings/' + recording_id + '/stop') return self.__wait_for_recording_status(recording_id, ['done']) == "done" def pause_recording(self, recording_id): + """Pause recording on the Tobii interface's SD Card.""" + super().post_request('/api/recordings/' + recording_id + '/pause') return self.__wait_for_recording_status(recording_id, ['paused']) == "paused" - def get_recording_status(self): + def __get_recording_status(self): return self.get_status()['sys_recording'] def get_current_recording_id(self): - return self.get_recording_status()['rec_id'] + return self.__get_recording_status()['rec_id'] def is_recording(self): - rec_status = self.get_recording_status() + rec_status = self.__get_recording_status() if rec_status != {}: if rec_status['rec_state'] == "recording": diff --git a/src/argaze/utils/README.md b/src/argaze/utils/README.md index ffe2c16..f03302c 100644 --- a/src/argaze/utils/README.md +++ b/src/argaze/utils/README.md @@ -39,7 +39,7 @@ python ./src/argaze/utils/live_tobii_session.py -t IP_ADDRESS - Record a Tobii Glasses Pro 2 'Test' session for a participant '1' on Tobii interface's SD card (replace IP_ADDRESS). ``` -python ./src/argaze/utils/record_tobii_session.py -t IP_ADDRESS -p Test -i 1 +python ./src/argaze/utils/record_tobii_session.py -t IP_ADDRESS -p myProject -u mySelf ``` - Explore Tobii Glasses Pro 2 interface's SD Card (replace DRIVE_PATH, PROJECT_PATH, RECORDING_PATH, SEGMENT_PATH) diff --git a/src/argaze/utils/calibrate_tobii_camera.py b/src/argaze/utils/calibrate_tobii_camera.py index 0381f75..cb4c792 100644 --- a/src/argaze/utils/calibrate_tobii_camera.py +++ b/src/argaze/utils/calibrate_tobii_camera.py @@ -34,7 +34,7 @@ def main(): args = parser.parse_args() # Create tobii controller - tobii_controller = TobiiController.TobiiController(args.tobii_ip, 'ArGaze', 1) + tobii_controller = TobiiController.TobiiController(args.tobii_ip, 'myProject', 'mySelf') # Enable tobii video stream tobii_video_stream = tobii_controller.enable_video_stream() diff --git a/src/argaze/utils/live_tobii_aruco_detection.py b/src/argaze/utils/live_tobii_aruco_detection.py index 82837d6..3b3640f 100644 --- a/src/argaze/utils/live_tobii_aruco_detection.py +++ b/src/argaze/utils/live_tobii_aruco_detection.py @@ -32,7 +32,7 @@ def main(): args = parser.parse_args() # Create tobii controller - tobii_controller = TobiiController.TobiiController(args.tobii_ip, 'ArGaze', 1) + tobii_controller = TobiiController.TobiiController(args.tobii_ip, 'myProject', 'mySelf') # Calibrate tobii glasses #tobii_controller.calibrate() diff --git a/src/argaze/utils/live_tobii_session.py b/src/argaze/utils/live_tobii_session.py index c78f058..6c58d10 100644 --- a/src/argaze/utils/live_tobii_session.py +++ b/src/argaze/utils/live_tobii_session.py @@ -21,7 +21,7 @@ def main(): args = parser.parse_args() # Create tobii controller - tobii_controller = TobiiController.TobiiController(args.tobii_ip, 'ArGaze', 1) + tobii_controller = TobiiController.TobiiController(args.tobii_ip, 'myProject', 'mySelf') # Calibrate tobii glasses tobii_controller.calibrate() diff --git a/src/argaze/utils/record_tobii_session.py b/src/argaze/utils/record_tobii_session.py index ecea08a..386acbf 100644 --- a/src/argaze/utils/record_tobii_session.py +++ b/src/argaze/utils/record_tobii_session.py @@ -12,33 +12,33 @@ def main(): Record a Tobii Glasses Pro 2 session on Tobii interface's SD Card """ - # manage arguments + # Manage arguments parser = argparse.ArgumentParser(description=main.__doc__.split('-')[0]) parser.add_argument('-t', '--tobii_ip', metavar='TOBII_IP', type=str, default='192.168.1.10', help='tobii glasses ip') - parser.add_argument('-p', '--project_name', metavar='PROJECT_NAME', type=str, default='Untitled project', help='project name') - parser.add_argument('-i', '--participant_id', metavar='PARTICIPANT_ID', type=int, default=1, help='participant identifier') + parser.add_argument('-p', '--project_name', metavar='PROJECT_NAME', type=str, default=TobiiController.DEFAULT_PROJECT_NAME, help='project name') + parser.add_argument('-u', '--participant_name', metavar='PARTICIPANT_NAME', type=str, default=TobiiController.DEFAULT_PARTICIPANT_NAME, help='participant name') args = parser.parse_args() - # create tobii controller - tobii_controller = TobiiController.TobiiController(args.tobii_ip, args.project_name, args.participant_id) + # Create tobii controller + tobii_controller = TobiiController.TobiiController(args.tobii_ip, args.project_name, args.participant_name) - # calibrate tobii glasses + # Calibrate tobii glasses tobii_controller.calibrate() - # start tobii glasses streaming - tobii_controller.start_streaming() + # Create recording + recording_id = tobii_controller.create_recording(args.participant_name) - # start recording - tobii_controller.record() + # Start recording + tobii_controller.start_recording(recording_id) - # waiting until keyboard interruption + # Waiting until keyboard interruption try: last_battery_level = 0 time_count = 0 while True: - # print storage info each minutes + # Print storage info each minutes if time_count % 60 == 0: print(tobii_controller.get_storage_info()) @@ -50,7 +50,7 @@ def main(): print(tobii_controller.get_battery_info()) last_battery_level = battery_level - # sleep + # Sleep 1 second time.sleep(1) time_count += 1 @@ -58,8 +58,8 @@ def main(): except KeyboardInterrupt: pass - # stop tobii glasses streaming - tobii_controller.stop_streaming() + # Stop recording + tobii_controller.stop_recording(recording_id) if __name__ == '__main__': -- cgit v1.1