Skip to content

DropsDriver

myClient

Source code in dod/DropsDriver.py
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
class myClient:
  def __init__(self, ip, port, supported_json="supported.json", reload=True, queue=None, **kwargs):
    # dto pipelines
    self.__queue__ = Queue()
    self.__queue_ready__ = Semaphore(value=0)
    # configure connection object
    self.__IP__ = ip
    self.__PORT__ = port
    self.conn = HTTPConnection(host=self.__IP__, port=self.__PORT__)
    self.transceiver = HTTPTransceiver(self.conn, self.__queue__, self.__queue_ready__)
    logger.info(f"Connected to ip: {ip} port: {port}")

    # configuration persitence, updating
    self.supported_ends_handler = SupportedEndsHandler(supported_json,self.conn)
    if (reload):
      self.supported_ends_handler.reload_all()

    # convinient member lambda for grabbing supported endpoitns
    self.supported_ends = lambda : self.supported_ends_handler.get_endpoints()
    pprint.pprint(self.supported_ends())

  def __del__(self):
      # close network connection
      self.conn.close()

  '''
  Middleware interaction defintions
  Here we define specific interactions that the machine is capable of fielding
  These actions are exposed as member functions of this driver class. 
  '''

  def middle_invocation_wrapper(func):
    '''
    Define a decorator function to adorn all of these 'high' middleware calls
    Logs what functions is being called and returns the response. 
    '''
    def inner(self, *args):
      logger.info(f"Invoking {func.__name__}")
      func(self, *args)
      resp = self.get_response()
      # TODO: Do something with None response globally
      # Check if we have a GUI (get_status) that needs to be cleared, May need
      # to happen per function basis
      return resp
    return inner

  @middle_invocation_wrapper
  def connect(self, user : str):
      """
        Required to send 'Do' requests
      """
      self.send(f"/DoD/Connect?ClientName={user}")

  @middle_invocation_wrapper
  def disconnect(self):
      """
        The client can end the connection with access to ‘Do’ requests.
        Clicking the button ‘Disable API Control’ on the UI has the same effect.
      """
      self.send("/DoD/Disconnect")

  @middle_invocation_wrapper
  def get_status(self):
      """
        Returns Robot Status
      """
      self.send("/DoD/get/Status")


  @middle_invocation_wrapper
  def move(self, position : str):
      """
        Moves the drive to a position taken from the list of 'PositionNames'
      """
      self.send(f"/DoD/do/Move?PositionName={position}")

  @middle_invocation_wrapper
  def get_position_names(self):
      """
        Returns the list of positions in DOD robot
      """
      self.send(f"/DoD/get/PositionNames")

  @middle_invocation_wrapper
  def get_task_names(self):
      """
        Returns the list of tasks that are stored in the Robot by name
      """
      self.send(f"/DoD/get/TaskNames")

  @middle_invocation_wrapper
  def get_current_positions(self):
      """
        Returns the name and properties of the last selected position,
        together with the real current position coordinates.
        (The drives can have been stepped away from the stored position or 
        they include small dispenser related offsets.)
      """
      self.send(f"/DoD/get/CurrentPosition")

  @middle_invocation_wrapper
  def execute_task(self, value : str):
      """
        Runs a task from the list of ‘TaskName’.
        This operation is safe in general.
        It simulates the analog action on the UI.
      """
      self.send(f"/DoD/do/ExecuteTask?TaskName={value}")

  @middle_invocation_wrapper
  def auto_drop(self):
      """
        Runs the particular task that is linked to the UI button.
        Its name is ‘AutoDropDetection’. In principalm this endpoint is not needed.
        ‘ExecuteTask’ can be used instead.
      """
      self.send(f"/DoD/do/AutoDrop")

  @middle_invocation_wrapper
  def move_to_interaction_point(self):
      """
        The moving to the predefined position of the interaction point corresponds
        to the use of the endpoint ‘Move’. But only with this endpoint the UI
        elemts for the dispensers’ position adjustment become visible on the UI.
        The request simulates the button (beam simbol) on the UI.
      """
      self.send(f"/DoD/do/InteractionPoint")

  @middle_invocation_wrapper
  def move_x(self, value : float):
      """
        The X drive can be sent to any coordinate (the value’s unit is µm)
        within the allowed range.

        NOTE: This does not include a Z move up to the safe height nor any
        other safety feature checking whether the move from the current position
        to the selected coordinate can lead to collision or breaking of a
        dispenser Tip.
      """
      self.send(f"/DoD/do/MoveX?X={value}")

    ## API V2
  @middle_invocation_wrapper
  def get_pulse_names(self):
      """
        Returns the list of available pulse shapes for the sciPULSE channels.
      """
      self.send(f"/DoD/get/PulseNames")

  @middle_invocation_wrapper
  def get_nozzle_status(self):
      """
        Returns the activated and selected nozzles an the parameters for all
        activated nozzles. The parameter ‘Trigger’ (true/false) is not linked
        to a nozzle.

        Note: Nozzle parameters
        ‘ID’ (number),
        ‘Volt’,
        ‘Pulse’ (name or number),
        ‘Freq’ ,
        ‘Volume’ appear as an array of strings (JSON).
      """
      self.send("/DoD/get/NozzleStatus")

  @middle_invocation_wrapper
  def select_nozzle(self, channel: str):
      """
        Set the selected nozzle for dispensing and task execution etc.
        Returns a reject if the channel value is not one of the
        ‘Activated Nozzles’ (see ‘NozzleStatus’).
      """
      self.send(f"/DoD/do/SelectNozzle?Channel={channel}")


  @middle_invocation_wrapper
  def dispensing(self, state: str):
      """
        Switches between the dispensing states
        ‘Trigger’ (includes ‘Stat Continuous Dispensing’),
        ‘Free’ (‘Continuous Dispensing’ without trigger) and
        ‘Off’. Returns a reject if the value is not one of the three strings.

        (Some tasks can set the state to ‘Off’ without restarting dispensing afterwards.)
      """
      self.send(f"/DoD/do/Dispensing?State={state}")


  @middle_invocation_wrapper
  def setLED(self, duration: int, delay : int):
      """
      Sets the two strobe LED parameters ‘Delay’ (0 to 6500) and Duration (1 to 65000).
      Returns a reject if one of the values is out of range.
      """
      self.send(f"/DoD/do/SetLED?Duration={duration}&Delay={delay}")

  @middle_invocation_wrapper
  def move_y(self, value : float):
      """
          Same as for Y
      """
      #TODO: handle Dialog, Caputure None, Check if dialog and clear
      self.send(f"/DoD/do/MoveY?Y={value}")

  @middle_invocation_wrapper
  def move_z(self, value : float):
      """
          Same as for Z
      """
      self.send(f"/DoD/do/MoveZ?Z={value}")

  @middle_invocation_wrapper
  def take_probe(self, channel : int, probe_well : str, volume : float):
      """
      This endpoint requires the presence of the task ‘ProbeUptake’ (attached).
      If that is not given, the return is not a reject, but nothing happens.
      The parameters are

        ‘Channel’ (number of nozzle, includes effect as ‘SelectNozzle’),
        ‘ProbeWell’ (e.g. A1), Volume (µL). Returns a reject  if ‘Channel’ is not among
        ‘Active Nozzles’, Volume is > 250 or
        ‘ProbeWell’ is not one of the allowed wells for the selected nozzle.

      """
      self.send(f"/DoD/do/TakeProbe?Channel={channel}&ProbeWell={probe_well}&Volume={volume}")

## API V3 ##

  @middle_invocation_wrapper
  def get_task_details(self, task_name):
    '''
        Returns the content of the tasks that is specified be ‘TaskName’.
    '''
    self.send(f"/DoD/get/TaskDetails?TaskName={task_name}")

  @middle_invocation_wrapper
  def get_drive_range(self):
    '''
      Returns the maximum range of each axis (X,Y,Z) in units of µm.
    '''
    self.send(f"/DoD/get/DriveRange")

  @middle_invocation_wrapper
  def set_nozzle_parameters(self,
                            active_nozzles : str,
                            selected_nozzles: str,
                            volts : int,
                            pulse : str,
                            frequency : int):
    '''
      Sets the list of activate nozzles and of the selected nozzles for
        operations that work with more than one nozzle.
      (This overwrites and is overwritten by SelectNozzle, which only sets one nozzle channel.)
      Both values are strings with commas separating the channel numbers (e.g. “1,2,3”).
      ‘Volt’ and ‘Freq’ are integers.
      ‘Pulse’ is read as a string. It is either a integer number or the pulse
        shape name for sciPULSE channels (from PulseNames).

    '''

    self.send(f"/DoD/do/SetNozzleParameters?Active={active_nozzles}&Selected={selected_nozzles}&Volt={volts}&Pulse={pulse}&Freq={frequency}")

  @middle_invocation_wrapper
  def stop_task(self):
    '''
            Stops the running task (and moves).
    '''
    self.send(f"/DoD/do/StopTask")

  @middle_invocation_wrapper
  def set_ip_offest(self):
    '''
            This endpoint uses the current coordinates for the currently selected
            nozzle (SelectNozzle) to set the IP position (Nozzle 1) or calculates
            and sets the IP offsets (Nozzles 2, …).
            (Note: The ‘Nozzle Offset’ values in the nozzle parameter table are 
            always considered.
            Changing these would require a readjustment of the IP offsets.)
            Offsets are rejected if they exceed a maximum of 2 mm.
            Thus, the selected nozzle must be moved to the IP (InteractionPoint)
            before requesting SetIPOffset.
    '''
    self.send(f"/DoD/do/InteractionPoint")

  @middle_invocation_wrapper
  def set_humidity(self, value):
    '''
        Sets the wanted relative humidity as %rH. Values are integer.
    '''
    self.send(f"/DoD/do/SetHumidity?rH={value}")

  @middle_invocation_wrapper
  def set_cooling_temp(self, temp):
    '''
            Sets the temperature of the cooling device.
            Besides the setting of a °C value (float),
                there is the option to send the string “dewpoint”,
                which enables an automatic adjustment.
    '''
    self.send(f"/DoD/do/SetCoolingTemp?Temp={temp}")

  @middle_invocation_wrapper
  def close_dialog(self, reference, selection):
    '''
            In situations of “Status” = “Dialog” the endpoint Status provides the
                dialog’s reference, message text and button labels.
            (If the response of ‘Button2’ is empty, there is only one selection 
            available, typically with the label ‘OK.).
            This endpoint allows to close the dialog by specifying the reference and t
                he selection (“1” or “2”).
            The reference is individual, incrementing integer for each occurrence
                of a dialog, it starts a “1” when the device is initialized.

            In case of more than one open dialogs “Status” reports the last one,
                which is typically the first to be closed.
            But the remote control can try to close the earlier dialog.
    '''
    self.send(f"/DoD/do/CloseDialog?Reference={reference}&Selection={selection}")

  @middle_invocation_wrapper
  def reset_error(self):
    '''
            This endpoint is needed if after closing all (error) dialogs the status 
            “Error” persists and “ErrorMessage” (header) is not “NA”.
    '''
    self.send(f"/DoD/do/ResetError")

  '''
  send transmits a formatted HTTP GET request
  it will not check the validity of request
  it will persist result in a place that can be read... TODO: actually do this
  '''
  def send(self, endpoint):
    self.transceiver.send(endpoint)
    return

  '''
  Pops most recent response from response queue
  '''
  def get_response(self):
    return self.transceiver.get_response()

auto_drop()

Runs the particular task that is linked to the UI button. Its name is ‘AutoDropDetection’. In principalm this endpoint is not needed. ‘ExecuteTask’ can be used instead.

Source code in dod/DropsDriver.py
147
148
149
150
151
152
153
154
@middle_invocation_wrapper
def auto_drop(self):
    """
      Runs the particular task that is linked to the UI button.
      Its name is ‘AutoDropDetection’. In principalm this endpoint is not needed.
      ‘ExecuteTask’ can be used instead.
    """
    self.send(f"/DoD/do/AutoDrop")

close_dialog(reference, selection)

In situations of “Status” = “Dialog” the endpoint Status provides the dialog’s reference, message text and button labels. (If the response of ‘Button2’ is empty, there is only one selection available, typically with the label ‘OK.). This endpoint allows to close the dialog by specifying the reference and t he selection (“1” or “2”). The reference is individual, incrementing integer for each occurrence of a dialog, it starts a “1” when the device is initialized.

In case of more than one open dialogs “Status” reports the last one, which is typically the first to be closed. But the remote control can try to close the earlier dialog.

Source code in dod/DropsDriver.py
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
@middle_invocation_wrapper
def close_dialog(self, reference, selection):
  '''
          In situations of “Status” = “Dialog” the endpoint Status provides the
              dialog’s reference, message text and button labels.
          (If the response of ‘Button2’ is empty, there is only one selection 
          available, typically with the label ‘OK.).
          This endpoint allows to close the dialog by specifying the reference and t
              he selection (“1” or “2”).
          The reference is individual, incrementing integer for each occurrence
              of a dialog, it starts a “1” when the device is initialized.

          In case of more than one open dialogs “Status” reports the last one,
              which is typically the first to be closed.
          But the remote control can try to close the earlier dialog.
  '''
  self.send(f"/DoD/do/CloseDialog?Reference={reference}&Selection={selection}")

connect(user)

Required to send 'Do' requests

Source code in dod/DropsDriver.py
84
85
86
87
88
89
@middle_invocation_wrapper
def connect(self, user : str):
    """
      Required to send 'Do' requests
    """
    self.send(f"/DoD/Connect?ClientName={user}")

disconnect()

The client can end the connection with access to ‘Do’ requests. Clicking the button ‘Disable API Control’ on the UI has the same effect.

Source code in dod/DropsDriver.py
91
92
93
94
95
96
97
@middle_invocation_wrapper
def disconnect(self):
    """
      The client can end the connection with access to ‘Do’ requests.
      Clicking the button ‘Disable API Control’ on the UI has the same effect.
    """
    self.send("/DoD/Disconnect")

dispensing(state)

Switches between the dispensing states ‘Trigger’ (includes ‘Stat Continuous Dispensing’), ‘Free’ (‘Continuous Dispensing’ without trigger) and ‘Off’. Returns a reject if the value is not one of the three strings.

(Some tasks can set the state to ‘Off’ without restarting dispensing afterwards.)

Source code in dod/DropsDriver.py
213
214
215
216
217
218
219
220
221
222
223
@middle_invocation_wrapper
def dispensing(self, state: str):
    """
      Switches between the dispensing states
      ‘Trigger’ (includes ‘Stat Continuous Dispensing’),
      ‘Free’ (‘Continuous Dispensing’ without trigger) and
      ‘Off’. Returns a reject if the value is not one of the three strings.

      (Some tasks can set the state to ‘Off’ without restarting dispensing afterwards.)
    """
    self.send(f"/DoD/do/Dispensing?State={state}")

execute_task(value)

Runs a task from the list of ‘TaskName’. This operation is safe in general. It simulates the analog action on the UI.

Source code in dod/DropsDriver.py
138
139
140
141
142
143
144
145
@middle_invocation_wrapper
def execute_task(self, value : str):
    """
      Runs a task from the list of ‘TaskName’.
      This operation is safe in general.
      It simulates the analog action on the UI.
    """
    self.send(f"/DoD/do/ExecuteTask?TaskName={value}")

get_current_positions()

Returns the name and properties of the last selected position, together with the real current position coordinates. (The drives can have been stepped away from the stored position or they include small dispenser related offsets.)

Source code in dod/DropsDriver.py
128
129
130
131
132
133
134
135
136
@middle_invocation_wrapper
def get_current_positions(self):
    """
      Returns the name and properties of the last selected position,
      together with the real current position coordinates.
      (The drives can have been stepped away from the stored position or 
      they include small dispenser related offsets.)
    """
    self.send(f"/DoD/get/CurrentPosition")

get_drive_range()

Returns the maximum range of each axis (X,Y,Z) in units of µm.

Source code in dod/DropsDriver.py
273
274
275
276
277
278
@middle_invocation_wrapper
def get_drive_range(self):
  '''
    Returns the maximum range of each axis (X,Y,Z) in units of µm.
  '''
  self.send(f"/DoD/get/DriveRange")

get_nozzle_status()

Returns the activated and selected nozzles an the parameters for all activated nozzles. The parameter ‘Trigger’ (true/false) is not linked to a nozzle.

Note: Nozzle parameters ‘ID’ (number), ‘Volt’, ‘Pulse’ (name or number), ‘Freq’ , ‘Volume’ appear as an array of strings (JSON).

Source code in dod/DropsDriver.py
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
@middle_invocation_wrapper
def get_nozzle_status(self):
    """
      Returns the activated and selected nozzles an the parameters for all
      activated nozzles. The parameter ‘Trigger’ (true/false) is not linked
      to a nozzle.

      Note: Nozzle parameters
      ‘ID’ (number),
      ‘Volt’,
      ‘Pulse’ (name or number),
      ‘Freq’ ,
      ‘Volume’ appear as an array of strings (JSON).
    """
    self.send("/DoD/get/NozzleStatus")

get_position_names()

Returns the list of positions in DOD robot

Source code in dod/DropsDriver.py
114
115
116
117
118
119
@middle_invocation_wrapper
def get_position_names(self):
    """
      Returns the list of positions in DOD robot
    """
    self.send(f"/DoD/get/PositionNames")

get_pulse_names()

Returns the list of available pulse shapes for the sciPULSE channels.

Source code in dod/DropsDriver.py
180
181
182
183
184
185
@middle_invocation_wrapper
def get_pulse_names(self):
    """
      Returns the list of available pulse shapes for the sciPULSE channels.
    """
    self.send(f"/DoD/get/PulseNames")

get_status()

Returns Robot Status

Source code in dod/DropsDriver.py
 99
100
101
102
103
104
@middle_invocation_wrapper
def get_status(self):
    """
      Returns Robot Status
    """
    self.send("/DoD/get/Status")

get_task_details(task_name)

Returns the content of the tasks that is specified be ‘TaskName’.

Source code in dod/DropsDriver.py
266
267
268
269
270
271
@middle_invocation_wrapper
def get_task_details(self, task_name):
  '''
      Returns the content of the tasks that is specified be ‘TaskName’.
  '''
  self.send(f"/DoD/get/TaskDetails?TaskName={task_name}")

get_task_names()

Returns the list of tasks that are stored in the Robot by name

Source code in dod/DropsDriver.py
121
122
123
124
125
126
@middle_invocation_wrapper
def get_task_names(self):
    """
      Returns the list of tasks that are stored in the Robot by name
    """
    self.send(f"/DoD/get/TaskNames")

middle_invocation_wrapper(func)

Define a decorator function to adorn all of these 'high' middleware calls Logs what functions is being called and returns the response.

Source code in dod/DropsDriver.py
69
70
71
72
73
74
75
76
77
78
79
80
81
82
def middle_invocation_wrapper(func):
  '''
  Define a decorator function to adorn all of these 'high' middleware calls
  Logs what functions is being called and returns the response. 
  '''
  def inner(self, *args):
    logger.info(f"Invoking {func.__name__}")
    func(self, *args)
    resp = self.get_response()
    # TODO: Do something with None response globally
    # Check if we have a GUI (get_status) that needs to be cleared, May need
    # to happen per function basis
    return resp
  return inner

move(position)

Moves the drive to a position taken from the list of 'PositionNames'

Source code in dod/DropsDriver.py
107
108
109
110
111
112
@middle_invocation_wrapper
def move(self, position : str):
    """
      Moves the drive to a position taken from the list of 'PositionNames'
    """
    self.send(f"/DoD/do/Move?PositionName={position}")

move_to_interaction_point()

The moving to the predefined position of the interaction point corresponds to the use of the endpoint ‘Move’. But only with this endpoint the UI elemts for the dispensers’ position adjustment become visible on the UI. The request simulates the button (beam simbol) on the UI.

Source code in dod/DropsDriver.py
156
157
158
159
160
161
162
163
164
@middle_invocation_wrapper
def move_to_interaction_point(self):
    """
      The moving to the predefined position of the interaction point corresponds
      to the use of the endpoint ‘Move’. But only with this endpoint the UI
      elemts for the dispensers’ position adjustment become visible on the UI.
      The request simulates the button (beam simbol) on the UI.
    """
    self.send(f"/DoD/do/InteractionPoint")

move_x(value)

The X drive can be sent to any coordinate (the value’s unit is µm) within the allowed range.

NOTE: This does not include a Z move up to the safe height nor any other safety feature checking whether the move from the current position to the selected coordinate can lead to collision or breaking of a dispenser Tip.

Source code in dod/DropsDriver.py
166
167
168
169
170
171
172
173
174
175
176
177
@middle_invocation_wrapper
def move_x(self, value : float):
    """
      The X drive can be sent to any coordinate (the value’s unit is µm)
      within the allowed range.

      NOTE: This does not include a Z move up to the safe height nor any
      other safety feature checking whether the move from the current position
      to the selected coordinate can lead to collision or breaking of a
      dispenser Tip.
    """
    self.send(f"/DoD/do/MoveX?X={value}")

move_y(value)

Same as for Y

Source code in dod/DropsDriver.py
234
235
236
237
238
239
240
@middle_invocation_wrapper
def move_y(self, value : float):
    """
        Same as for Y
    """
    #TODO: handle Dialog, Caputure None, Check if dialog and clear
    self.send(f"/DoD/do/MoveY?Y={value}")

move_z(value)

Same as for Z

Source code in dod/DropsDriver.py
242
243
244
245
246
247
@middle_invocation_wrapper
def move_z(self, value : float):
    """
        Same as for Z
    """
    self.send(f"/DoD/do/MoveZ?Z={value}")

reset_error()

This endpoint is needed if after closing all (error) dialogs the status “Error” persists and “ErrorMessage” (header) is not “NA”.

Source code in dod/DropsDriver.py
357
358
359
360
361
362
363
@middle_invocation_wrapper
def reset_error(self):
  '''
          This endpoint is needed if after closing all (error) dialogs the status 
          “Error” persists and “ErrorMessage” (header) is not “NA”.
  '''
  self.send(f"/DoD/do/ResetError")

select_nozzle(channel)

Set the selected nozzle for dispensing and task execution etc. Returns a reject if the channel value is not one of the ‘Activated Nozzles’ (see ‘NozzleStatus’).

Source code in dod/DropsDriver.py
203
204
205
206
207
208
209
210
@middle_invocation_wrapper
def select_nozzle(self, channel: str):
    """
      Set the selected nozzle for dispensing and task execution etc.
      Returns a reject if the channel value is not one of the
      ‘Activated Nozzles’ (see ‘NozzleStatus’).
    """
    self.send(f"/DoD/do/SelectNozzle?Channel={channel}")

setLED(duration, delay)

Sets the two strobe LED parameters ‘Delay’ (0 to 6500) and Duration (1 to 65000). Returns a reject if one of the values is out of range.

Source code in dod/DropsDriver.py
226
227
228
229
230
231
232
@middle_invocation_wrapper
def setLED(self, duration: int, delay : int):
    """
    Sets the two strobe LED parameters ‘Delay’ (0 to 6500) and Duration (1 to 65000).
    Returns a reject if one of the values is out of range.
    """
    self.send(f"/DoD/do/SetLED?Duration={duration}&Delay={delay}")

set_cooling_temp(temp)

Sets the temperature of the cooling device. Besides the setting of a °C value (float), there is the option to send the string “dewpoint”, which enables an automatic adjustment.

Source code in dod/DropsDriver.py
329
330
331
332
333
334
335
336
337
@middle_invocation_wrapper
def set_cooling_temp(self, temp):
  '''
          Sets the temperature of the cooling device.
          Besides the setting of a °C value (float),
              there is the option to send the string “dewpoint”,
              which enables an automatic adjustment.
  '''
  self.send(f"/DoD/do/SetCoolingTemp?Temp={temp}")

set_humidity(value)

Sets the wanted relative humidity as %rH. Values are integer.

Source code in dod/DropsDriver.py
322
323
324
325
326
327
@middle_invocation_wrapper
def set_humidity(self, value):
  '''
      Sets the wanted relative humidity as %rH. Values are integer.
  '''
  self.send(f"/DoD/do/SetHumidity?rH={value}")

set_ip_offest()

This endpoint uses the current coordinates for the currently selected nozzle (SelectNozzle) to set the IP position (Nozzle 1) or calculates and sets the IP offsets (Nozzles 2, …). (Note: The ‘Nozzle Offset’ values in the nozzle parameter table are always considered. Changing these would require a readjustment of the IP offsets.) Offsets are rejected if they exceed a maximum of 2 mm. Thus, the selected nozzle must be moved to the IP (InteractionPoint) before requesting SetIPOffset.

Source code in dod/DropsDriver.py
307
308
309
310
311
312
313
314
315
316
317
318
319
320
@middle_invocation_wrapper
def set_ip_offest(self):
  '''
          This endpoint uses the current coordinates for the currently selected
          nozzle (SelectNozzle) to set the IP position (Nozzle 1) or calculates
          and sets the IP offsets (Nozzles 2, …).
          (Note: The ‘Nozzle Offset’ values in the nozzle parameter table are 
          always considered.
          Changing these would require a readjustment of the IP offsets.)
          Offsets are rejected if they exceed a maximum of 2 mm.
          Thus, the selected nozzle must be moved to the IP (InteractionPoint)
          before requesting SetIPOffset.
  '''
  self.send(f"/DoD/do/InteractionPoint")

set_nozzle_parameters(active_nozzles, selected_nozzles, volts, pulse, frequency)

Sets the list of activate nozzles and of the selected nozzles for operations that work with more than one nozzle. (This overwrites and is overwritten by SelectNozzle, which only sets one nozzle channel.) Both values are strings with commas separating the channel numbers (e.g. “1,2,3”). ‘Volt’ and ‘Freq’ are integers. ‘Pulse’ is read as a string. It is either a integer number or the pulse shape name for sciPULSE channels (from PulseNames).

Source code in dod/DropsDriver.py
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
@middle_invocation_wrapper
def set_nozzle_parameters(self,
                          active_nozzles : str,
                          selected_nozzles: str,
                          volts : int,
                          pulse : str,
                          frequency : int):
  '''
    Sets the list of activate nozzles and of the selected nozzles for
      operations that work with more than one nozzle.
    (This overwrites and is overwritten by SelectNozzle, which only sets one nozzle channel.)
    Both values are strings with commas separating the channel numbers (e.g. “1,2,3”).
    ‘Volt’ and ‘Freq’ are integers.
    ‘Pulse’ is read as a string. It is either a integer number or the pulse
      shape name for sciPULSE channels (from PulseNames).

  '''

  self.send(f"/DoD/do/SetNozzleParameters?Active={active_nozzles}&Selected={selected_nozzles}&Volt={volts}&Pulse={pulse}&Freq={frequency}")

stop_task()

Stops the running task (and moves).

Source code in dod/DropsDriver.py
300
301
302
303
304
305
@middle_invocation_wrapper
def stop_task(self):
  '''
          Stops the running task (and moves).
  '''
  self.send(f"/DoD/do/StopTask")

take_probe(channel, probe_well, volume)

This endpoint requires the presence of the task ‘ProbeUptake’ (attached). If that is not given, the return is not a reject, but nothing happens. The parameters are

‘Channel’ (number of nozzle, includes effect as ‘SelectNozzle’), ‘ProbeWell’ (e.g. A1), Volume (µL). Returns a reject if ‘Channel’ is not among ‘Active Nozzles’, Volume is > 250 or ‘ProbeWell’ is not one of the allowed wells for the selected nozzle.

Source code in dod/DropsDriver.py
249
250
251
252
253
254
255
256
257
258
259
260
261
262
@middle_invocation_wrapper
def take_probe(self, channel : int, probe_well : str, volume : float):
    """
    This endpoint requires the presence of the task ‘ProbeUptake’ (attached).
    If that is not given, the return is not a reject, but nothing happens.
    The parameters are

      ‘Channel’ (number of nozzle, includes effect as ‘SelectNozzle’),
      ‘ProbeWell’ (e.g. A1), Volume (µL). Returns a reject  if ‘Channel’ is not among
      ‘Active Nozzles’, Volume is > 250 or
      ‘ProbeWell’ is not one of the allowed wells for the selected nozzle.

    """
    self.send(f"/DoD/do/TakeProbe?Channel={channel}&ProbeWell={probe_well}&Volume={volume}")