From d11f9ccff13019d482632eace92c65602e179bca Mon Sep 17 00:00:00 2001 From: DerickLagunes Date: Sun, 3 Dec 2023 13:53:02 -0600 Subject: [PATCH] I have modified the opengaze.py to implement the new blink data from the GazePoint API changes in 2015: Refer to this post: https://www.gazept.com/blog/analysis/gazepoint-analysis-v3-0-0-blink-tracking/ I added the data header for: 'BKID', 'BKDUR' & 'BKPMIN' And the class method "enable_send_blink" which sends the signal to retrieve Blink data from the GazePoint API. This method is also called at the end of the constructor by default but can be controlled too. I have also implemented a "get_sample" method by using a list variable "_data_stream" created in the constructor, the list appends the lines created at the _log_sample method, this funtionalyty can be turn on by the user at the constructor with a boolean value "data_stream" Hope this functionality is uselful for researchers, it was for me because i had to make use of blink metrics. --- pygaze/_eyetracker/opengaze.py | 49 +++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/pygaze/_eyetracker/opengaze.py b/pygaze/_eyetracker/opengaze.py index 07420bf..e54654c 100644 --- a/pygaze/_eyetracker/opengaze.py +++ b/pygaze/_eyetracker/opengaze.py @@ -29,7 +29,7 @@ class OpenGazeTracker: def __init__(self, ip='127.0.0.1', port=4242, logfile='default.tsv', \ - debug=False): + debug=False, data_stream=False): """The OpenGazeConnection class communicates to the GazePoint server through a TCP/IP socket. Incoming samples will be written @@ -101,7 +101,13 @@ def __init__(self, ip='127.0.0.1', port=4242, logfile='default.tsv', \ 'LEYEX', 'LEYEY', 'LEYEZ', 'LPUPILD', 'LPUPILV', \ 'REYEX', 'REYEY', 'REYEZ', 'RPUPILD', 'RPUPILV', \ 'CX', 'CY', 'CS', \ + 'BKID', 'BKDUR', 'BKPMIN', \ 'USER'] + # Boolean to check whenever the user wants to save + # data samples + self.data_stream = data_stream + # List to store Eyetracker data samples + self._data_stream = [] self._n_logvars = len(self._logheader) self._logfile.write('\t'.join(self._logheader) + '\n') # The log is consolidated (written to the disk) every N samples. @@ -191,7 +197,9 @@ def __init__(self, ip='127.0.0.1', port=4242, logfile='default.tsv', \ self.enable_send_pupil_right(True) self.enable_send_time(True) self.enable_send_time_tick(True) + self.enable_send_blink(True) self.enable_send_user_data(True) + def calibrate(self): @@ -319,6 +327,11 @@ def _log_sample(self, sample): # Find the appropriate index in the line line[self._logheader.index(varname)] = sample[varname] self._logfile.write('\t'.join(line) + '\n') + # Store the sample in _data_stream: + # Only if user decided so in the data_stream + # Boolean variable at constructor + if self.data_stream: + self._data_stream.append(line) def _parse_msg(self, xml): @@ -823,6 +836,27 @@ def enable_send_cursor(self, state): # Return a success Boolean. return acknowledged and (timeout==False) + def enable_send_blink(self, state): + + """Enable (state=True) or disable (state=False) the inclusion of + Blink tracking, which has been added to the latest release of the + Gazepoint software (V3.0.0). one can access the blink tracking data + by enabling the ENABLE_SEND_BLINK setting which consists of the + following data: + BKID: A a blink counter. + BKDUR: Blink duration for the last blink. + BKPMIN: The average blink rate over the last minute. + """ + + # Send the message (returns after the Server acknowledges receipt). + acknowledged, timeout = self._send_message('SET', \ + 'ENABLE_SEND_BLINK', \ + values=[('STATE', int(state))], \ + wait_for_acknowledgement=True) + + # Return a success Boolean. + return acknowledged and (timeout==False) + def enable_send_user_data(self, state): """Enable (state=True) or disable (state=False) the inclusion of @@ -1378,4 +1412,17 @@ def get_api_id(self): return value # TODO: Get sample method. + # My approach to sample method + def get_sample(self): + """Gets a sample from the list that stored all samples. + should be used when data_stream = TRUE. + Returns a data vector from the logged data, 1 at a time. + or + returns None if the are none vectors left. + """ + if len(self._data_stream) > 0: + return self._data_stream.pop(0) + else: + return None + # TODO: Write sample method?