pychemstation 0.10.11__py3-none-any.whl → 0.10.12__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,131 @@
1
+ from __future__ import annotations
2
+
3
+ import warnings
4
+
5
+ from ....utils.macro import Command
6
+ from ....control.controllers import CommunicationController
7
+ from ....utils.abc_tables.device import DeviceController
8
+ from ....utils.device_types import (
9
+ SolventBottle,
10
+ MaybeBottle,
11
+ MaybePumpPosition,
12
+ PumpValve,
13
+ PumpPosition,
14
+ )
15
+ from ....utils.table_types import Table, RegisterFlag, Device
16
+
17
+
18
+ class PumpController(DeviceController):
19
+ def __init__(
20
+ self, controller: CommunicationController, table: Table | Device, offline: bool
21
+ ):
22
+ super().__init__(controller, table, offline)
23
+ self.A_position: MaybePumpPosition = (
24
+ self.load_pump_position(PumpValve.A) if not offline else None
25
+ )
26
+ self.B_position: MaybePumpPosition = (
27
+ self.load_pump_position(PumpValve.B) if not offline else None
28
+ )
29
+ self.A1: MaybeBottle = None
30
+ self.A2: MaybeBottle = None
31
+ self.B1: MaybeBottle = None
32
+ self.B2: MaybeBottle = None
33
+ self.waste_bottle: MaybeBottle = None
34
+
35
+ def load_pump_position(self, pump_valve: PumpValve) -> PumpPosition:
36
+ match pump_valve:
37
+ case PumpValve.A:
38
+ return PumpPosition.from_str(
39
+ self._read_str_param(RegisterFlag.PUMPCHANNEL_SELECTION)
40
+ )
41
+ case PumpValve.B:
42
+ return PumpPosition.from_str(
43
+ self._read_str_param(RegisterFlag.PUMPCHANNEL2_SELECTION)
44
+ )
45
+ case _:
46
+ raise ValueError("Expected one of PumpValve.A or PumpValve.B")
47
+
48
+ def load_bottles(self):
49
+ self.A1 = self.get_solvent_bottle_a1()
50
+ self.A2 = self.get_solvent_bottle_a2()
51
+ self.B1 = self.get_solvent_bottle_b1()
52
+ self.B2 = self.get_solvent_bottle_b2()
53
+
54
+ @property
55
+ def rinse_method(self):
56
+ return self._rinse_method
57
+
58
+ @rinse_method.setter
59
+ def rinse_method(self, new_rinse_method: str):
60
+ self._rinse_method = new_rinse_method
61
+
62
+ def turn_off(self):
63
+ self.send(Command.PUMP_OFF_CMD)
64
+
65
+ def turn_on(self):
66
+ self.send(Command.PUMP_ON_CMD)
67
+
68
+ def get_solvent_bottle_a1(self) -> SolventBottle:
69
+ return SolventBottle(
70
+ absolute_filled=self._read_num_param(
71
+ RegisterFlag.BOTTLE_A1_ABSOLUTE_FILLING
72
+ ),
73
+ percent_filled=self._read_num_param(RegisterFlag.BOTTLE_A1_PERCENT_FILLING),
74
+ max_volume=self._read_num_param(RegisterFlag.BOTTLE_A1_MAX),
75
+ in_use=self.A_position == PumpPosition.ONE,
76
+ user_name=self._read_str_param(RegisterFlag.BOTTLE_A1_USER_NAME),
77
+ type=PumpValve.A,
78
+ )
79
+
80
+ def get_solvent_bottle_a2(self) -> SolventBottle:
81
+ return SolventBottle(
82
+ absolute_filled=self._read_num_param(
83
+ RegisterFlag.BOTTLE_A2_ABSOLUTE_FILLING
84
+ ),
85
+ percent_filled=self._read_num_param(RegisterFlag.BOTTLE_A2_PERCENT_FILLING),
86
+ max_volume=self._read_num_param(RegisterFlag.BOTTLE_A2_MAX),
87
+ in_use=self.A_position == PumpPosition.TWO,
88
+ user_name=self._read_str_param(RegisterFlag.BOTTLE_A2_USER_NAME),
89
+ type=PumpValve.A,
90
+ )
91
+
92
+ def get_solvent_bottle_b1(self) -> SolventBottle:
93
+ return SolventBottle(
94
+ absolute_filled=self._read_num_param(
95
+ RegisterFlag.BOTTLE_B1_ABSOLUTE_FILLING
96
+ ),
97
+ percent_filled=self._read_num_param(RegisterFlag.BOTTLE_B1_PERCENT_FILLING),
98
+ max_volume=self._read_num_param(RegisterFlag.BOTTLE_B1_MAX),
99
+ in_use=self.A_position == PumpPosition.ONE,
100
+ user_name=self._read_str_param(RegisterFlag.BOTTLE_B1_USER_NAME),
101
+ type=PumpValve.B,
102
+ )
103
+
104
+ def get_solvent_bottle_b2(self) -> SolventBottle:
105
+ return SolventBottle(
106
+ absolute_filled=self._read_num_param(
107
+ RegisterFlag.BOTTLE_B2_ABSOLUTE_FILLING
108
+ ),
109
+ percent_filled=self._read_num_param(RegisterFlag.BOTTLE_B2_PERCENT_FILLING),
110
+ max_volume=self._read_num_param(RegisterFlag.BOTTLE_B2_MAX),
111
+ in_use=self.A_position == PumpPosition.TWO,
112
+ user_name=self._read_str_param(RegisterFlag.BOTTLE_B2_USER_NAME),
113
+ type=PumpValve.B,
114
+ )
115
+
116
+ def get_waste_bottle_stats(self):
117
+ max_vol = None
118
+ try:
119
+ max_vol = self._read_num_param(RegisterFlag.WASTE_BOTTLE_MAX)
120
+ except RuntimeError:
121
+ warnings.warn(
122
+ "No maximum volume available! All other SolventBottle parameters may not be reliable."
123
+ )
124
+ self.waste_bottle = SolventBottle(
125
+ absolute_filled=self._read_num_param(RegisterFlag.WASTE_BOTTLE_PERCENT),
126
+ percent_filled=self._read_num_param(RegisterFlag.WASTE_BOTTLE_ABSOLUTE),
127
+ max_volume=max_vol,
128
+ in_use=True,
129
+ user_name="Waste Bottle",
130
+ type=None,
131
+ )
@@ -0,0 +1,27 @@
1
+ from ....control.controllers import CommunicationController
2
+ from ....utils.abc_tables.device import DeviceController
3
+ from ....utils.table_types import Table, Device, RegisterFlag
4
+ from ....utils.tray_types import Tray, VialBar, FiftyFourVialPlate
5
+
6
+
7
+ class SampleInfo(DeviceController):
8
+ def turn_off(self):
9
+ raise NotImplementedError
10
+
11
+ def turn_on(self):
12
+ raise NotImplementedError
13
+
14
+ def __init__(
15
+ self, controller: CommunicationController, table: Table | Device, offline: bool
16
+ ):
17
+ super().__init__(controller, table, offline)
18
+
19
+ def get_location(self) -> Tray:
20
+ location = self._read_str_param(RegisterFlag.VIAL_NUMBER)
21
+ try:
22
+ return FiftyFourVialPlate.from_int(location)
23
+ except ValueError:
24
+ try:
25
+ return VialBar(location)
26
+ except ValueError:
27
+ raise ValueError("Could not read vial location.")
@@ -9,19 +9,20 @@ from __future__ import annotations
9
9
  import os.path
10
10
  from typing import Dict, List, Optional, Tuple, Union
11
11
 
12
- from pychemstation.analysis.chromatogram import AgilentChannelChromatogramData
13
- from pychemstation.analysis.chromatogram import (
14
- AgilentHPLCChromatogram,
15
- )
12
+ from .controllers.devices.column import ColumnController
13
+ from .controllers.devices.dad import DADController
16
14
  from .controllers.devices.injector import InjectorController
17
15
  from .controllers.data_aq.sequence import SequenceController, MethodController
16
+ from .controllers.devices.pump import PumpController
17
+ from .controllers.devices.sample_info import SampleInfo
18
+ from ..analysis import AgilentHPLCChromatogram, AgilentChannelChromatogramData
18
19
  from ..analysis.process_report import AgilentReport, ReportType
19
20
  from ..control.controllers import CommunicationController
20
21
  from ..utils.injector_types import InjectorTable
21
22
  from ..utils.macro import Command, Response, Status
22
23
  from ..utils.method_types import MethodDetails
23
24
  from ..utils.sequence_types import SequenceTable, SequenceDataFiles
24
- from ..utils.table_types import Table
25
+ from ..utils.table_types import Table, Device
25
26
 
26
27
 
27
28
  class HPLCController:
@@ -32,7 +33,15 @@ class HPLCController:
32
33
 
33
34
  INJECTOR_TABLE = Table(register="RCWLS1Pretreatment[1]", name="InstructionTable")
34
35
 
35
- MSD_TABLE = Table(register="MSACQINFO[1]", name="SprayChamber")
36
+ PUMP_DEVICE = Device(register="RCPMP1Status")
37
+
38
+ INJECTOR_DEVICE = Device(register="RCWLS1Method")
39
+
40
+ SAMPLE_INFO = Table(register="_CONFIG", name="SampleInfo")
41
+
42
+ COLUMN_TEMP_DEVICE = Device(register="RCTHM1Method")
43
+
44
+ DAD_DEVICE = Device(register="RCDAD1Method")
36
45
 
37
46
  def __init__(
38
47
  self,
@@ -68,9 +77,21 @@ class HPLCController:
68
77
  data_dirs=data_dirs,
69
78
  table=self.METHOD_TIMETABLE,
70
79
  offline=offline,
71
- injector_controller=InjectorController(
80
+ injector=InjectorController(
72
81
  controller=self.comm, table=self.INJECTOR_TABLE, offline=offline
73
82
  ),
83
+ pump=PumpController(
84
+ controller=self.comm, table=self.PUMP_DEVICE, offline=offline
85
+ ),
86
+ dad=DADController(
87
+ controller=self.comm, table=self.DAD_DEVICE, offline=offline
88
+ ),
89
+ column=ColumnController(
90
+ controller=self.comm, table=self.COLUMN_TEMP_DEVICE, offline=offline
91
+ ),
92
+ sample_info=SampleInfo(
93
+ controller=self.comm, table=self.SAMPLE_INFO, offline=offline
94
+ ),
74
95
  )
75
96
  self.sequence_controller: SequenceController = SequenceController(
76
97
  controller=self.comm,
@@ -304,7 +325,10 @@ class HPLCController:
304
325
  return self.sequence_controller.load()
305
326
 
306
327
  def load_injector_program(self) -> InjectorTable | None:
307
- return self.method_controller.injector_controller.load()
328
+ return self.method_controller.injector.load()
329
+
330
+ def load_sample_location(self):
331
+ self.method_controller.get_location()
308
332
 
309
333
  def standby(self):
310
334
  """Switches all modules in standby mode. All lamps and pumps are switched off."""
@@ -316,19 +340,19 @@ class HPLCController:
316
340
 
317
341
  def lamp_on(self):
318
342
  """Turns the UV lamp on."""
319
- self.send(Command.LAMP_ON_CMD)
343
+ self.method_controller.dad.turn_on()
320
344
 
321
345
  def lamp_off(self):
322
346
  """Turns the UV lamp off."""
323
- self.send(Command.LAMP_OFF_CMD)
347
+ self.method_controller.dad.turn_off()
324
348
 
325
349
  def pump_on(self):
326
350
  """Turns on the pump on."""
327
- self.send(Command.PUMP_ON_CMD)
351
+ self.method_controller.pump.turn_on()
328
352
 
329
353
  def pump_off(self):
330
354
  """Turns the pump off."""
331
- self.send(Command.PUMP_OFF_CMD)
355
+ self.method_controller.pump.turn_off()
332
356
 
333
357
  def instrument_off(self):
334
358
  """Shuts the entire instrument off, including pumps, lamps, thermostat."""
@@ -1,9 +1,9 @@
1
1
  from __future__ import annotations
2
2
 
3
- from abc import ABC
3
+ from abc import ABC, abstractmethod
4
4
 
5
5
  from .table import ABCTableController
6
- from ..table_types import Table
6
+ from ..table_types import Table, Device
7
7
  from ...control.controllers import CommunicationController
8
8
 
9
9
 
@@ -15,8 +15,11 @@ class DeviceController(ABCTableController, ABC):
15
15
  :param offline: whether the communication controller is online.
16
16
  """
17
17
 
18
+ def get_row(self, row: int):
19
+ raise NotImplementedError
20
+
18
21
  def __init__(
19
- self, controller: CommunicationController, table: Table, offline: bool
22
+ self, controller: CommunicationController, table: Table | Device, offline: bool
20
23
  ):
21
24
  super().__init__(controller=controller, table=table)
22
25
  self.offline = offline
@@ -25,3 +28,14 @@ class DeviceController(ABCTableController, ABC):
25
28
  if cls is ABCTableController:
26
29
  raise TypeError(f"only children of '{cls.__name__}' may be instantiated")
27
30
  return object.__new__(cls)
31
+
32
+ def download(self):
33
+ raise NotImplementedError
34
+
35
+ @abstractmethod
36
+ def turn_off(self):
37
+ pass
38
+
39
+ @abstractmethod
40
+ def turn_on(self):
41
+ pass
@@ -7,14 +7,16 @@ Authors: Lucy Hao
7
7
  from __future__ import annotations
8
8
 
9
9
  import abc
10
+ from abc import abstractmethod
11
+ from collections.abc import Callable
10
12
  from typing import Optional, Union
11
13
 
12
14
  from result import Err, Result
13
15
 
14
16
  from ..macro import Command, Response
15
- from ..method_types import MethodDetails
17
+ from ..method_types import MethodDetails, PType, Param
16
18
  from ..sequence_types import SequenceTable
17
- from ..table_types import Table, RegisterFlag, TableOperation
19
+ from ..table_types import Table, RegisterFlag, TableOperation, Device
18
20
  from ...control.controllers import CommunicationController
19
21
 
20
22
  TableType = Union[MethodDetails, SequenceTable]
@@ -29,7 +31,7 @@ class ABCTableController(abc.ABC):
29
31
  def __init__(
30
32
  self,
31
33
  controller: Optional[CommunicationController],
32
- table: Table,
34
+ table: Table | Device,
33
35
  ):
34
36
  self.controller = controller
35
37
  self.table_locator = table
@@ -40,6 +42,14 @@ class ABCTableController(abc.ABC):
40
42
  raise TypeError(f"only children of '{cls.__name__}' may be instantiated")
41
43
  return object.__new__(cls, *args, **kwargs)
42
44
 
45
+ @abstractmethod
46
+ def download(self):
47
+ pass
48
+
49
+ @abc.abstractmethod
50
+ def get_row(self, row: int):
51
+ pass
52
+
43
53
  def receive(self) -> Result[Response, str]:
44
54
  if self.controller:
45
55
  for _ in range(10):
@@ -72,7 +82,7 @@ class ABCTableController(abc.ABC):
72
82
  self.send(Command.SLEEP_CMD.value.format(seconds=seconds))
73
83
 
74
84
  def get_num(self, row: int, col_name: RegisterFlag) -> Union[int, float]:
75
- if self.controller:
85
+ if isinstance(self.table_locator, Table) and self.controller:
76
86
  return self.controller.get_num_val(
77
87
  TableOperation.GET_ROW_VAL.value.format(
78
88
  register=self.table_locator.register,
@@ -85,7 +95,7 @@ class ABCTableController(abc.ABC):
85
95
  raise ValueError("Controller is offline")
86
96
 
87
97
  def get_text(self, row: int, col_name: RegisterFlag) -> str:
88
- if self.controller:
98
+ if isinstance(self.table_locator, Table) and self.controller:
89
99
  return self.controller.get_text_val(
90
100
  TableOperation.GET_ROW_TEXT.value.format(
91
101
  register=self.table_locator.register,
@@ -100,26 +110,32 @@ class ABCTableController(abc.ABC):
100
110
  def add_new_col_num(self, col_name: RegisterFlag, val: Union[int, float]):
101
111
  if not (isinstance(val, int) or isinstance(val, float)):
102
112
  raise ValueError(f"{val} must be an int or float.")
103
- self.sleepy_send(
104
- TableOperation.NEW_COL_VAL.value.format(
105
- register=self.table_locator.register,
106
- table_name=self.table_locator.name,
107
- col_name=col_name,
108
- val=val,
113
+ if isinstance(self.table_locator, Table) and self.controller:
114
+ self.sleepy_send(
115
+ TableOperation.NEW_COL_VAL.value.format(
116
+ register=self.table_locator.register,
117
+ table_name=self.table_locator.name,
118
+ col_name=col_name,
119
+ val=val,
120
+ )
109
121
  )
110
- )
122
+ else:
123
+ raise ValueError("require table, not device")
111
124
 
112
125
  def add_new_col_text(self, col_name: RegisterFlag, val: str):
113
126
  if not isinstance(val, str):
114
127
  raise ValueError(f"{val} must be a str.")
115
- self.sleepy_send(
116
- TableOperation.NEW_COL_TEXT.value.format(
117
- register=self.table_locator.register,
118
- table_name=self.table_locator.name,
119
- col_name=col_name,
120
- val=val,
128
+ if isinstance(self.table_locator, Table) and self.controller:
129
+ self.sleepy_send(
130
+ TableOperation.NEW_COL_TEXT.value.format(
131
+ register=self.table_locator.register,
132
+ table_name=self.table_locator.name,
133
+ col_name=col_name,
134
+ val=val,
135
+ )
121
136
  )
122
- )
137
+ else:
138
+ raise ValueError("require table not device")
123
139
 
124
140
  def _edit_row_num(
125
141
  self, col_name: RegisterFlag, val: Union[int, float], row: Optional[int] = None
@@ -130,15 +146,16 @@ class ABCTableController(abc.ABC):
130
146
  if row and num_rows < row:
131
147
  raise ValueError("Not enough rows to edit!")
132
148
 
133
- self.sleepy_send(
134
- TableOperation.EDIT_ROW_VAL.value.format(
135
- register=self.table_locator.register,
136
- table_name=self.table_locator.name,
137
- row=row if row is not None else "response_num",
138
- col_name=col_name,
139
- val=val,
149
+ if isinstance(self.table_locator, Table) and self.controller:
150
+ self.sleepy_send(
151
+ TableOperation.EDIT_ROW_VAL.value.format(
152
+ register=self.table_locator.register,
153
+ table_name=self.table_locator.name,
154
+ row=row if row is not None else "response_num",
155
+ col_name=col_name,
156
+ val=val,
157
+ )
140
158
  )
141
- )
142
159
 
143
160
  def _edit_row_text(
144
161
  self, col_name: RegisterFlag, val: str, row: Optional[int] = None
@@ -149,28 +166,28 @@ class ABCTableController(abc.ABC):
149
166
  if row and num_rows < row:
150
167
  raise ValueError("Not enough rows to edit!")
151
168
 
152
- self.sleepy_send(
153
- TableOperation.EDIT_ROW_TEXT.value.format(
154
- register=self.table_locator.register,
155
- table_name=self.table_locator.name,
156
- row=row if row is not None else "response_num",
157
- col_name=col_name,
158
- val=val,
169
+ if isinstance(self.table_locator, Table) and self.controller:
170
+ self.sleepy_send(
171
+ TableOperation.EDIT_ROW_TEXT.value.format(
172
+ register=self.table_locator.register,
173
+ table_name=self.table_locator.name,
174
+ row=row if row is not None else "response_num",
175
+ col_name=col_name,
176
+ val=val,
177
+ )
159
178
  )
160
- )
161
-
162
- @abc.abstractmethod
163
- def get_row(self, row: int):
164
- pass
165
179
 
166
180
  def delete_row(self, row: int):
167
- self.sleepy_send(
168
- TableOperation.DELETE_ROW.value.format(
169
- register=self.table_locator.register,
170
- table_name=self.table_locator.name,
171
- row=row,
181
+ if isinstance(self.table_locator, Table) and self.controller:
182
+ self.sleepy_send(
183
+ TableOperation.DELETE_ROW.value.format(
184
+ register=self.table_locator.register,
185
+ table_name=self.table_locator.name,
186
+ row=row,
187
+ )
172
188
  )
173
- )
189
+ else:
190
+ raise ValueError("controller is offline or given device, need table")
174
191
 
175
192
  def get_row_count_safely(self) -> int:
176
193
  row_count = self.get_num_rows()
@@ -213,29 +230,95 @@ class ABCTableController(abc.ABC):
213
230
  )
214
231
 
215
232
  def get_num_rows(self) -> Result[Response, str]:
216
- self.send(
217
- Command.GET_ROWS_CMD.value.format(
218
- register=self.table_locator.register,
219
- table_name=self.table_locator.name,
220
- col_name=RegisterFlag.NUM_ROWS,
233
+ if isinstance(self.table_locator, Table) and self.controller:
234
+ self.send(
235
+ Command.GET_ROWS_CMD.value.format(
236
+ register=self.table_locator.register,
237
+ table_name=self.table_locator.name,
238
+ col_name=RegisterFlag.NUM_ROWS,
239
+ )
221
240
  )
222
- )
223
- if self.controller:
224
241
  res = self.controller.receive()
242
+ if res.is_ok():
243
+ return res
244
+ else:
245
+ return Err("No rows could be read.")
225
246
  else:
226
- raise ValueError("Controller is offline")
247
+ raise ValueError(
248
+ "controller was offline or was given a device and not a table"
249
+ )
227
250
 
228
- if res.is_ok():
229
- return res
251
+ def move_row(self, from_row: int, to_row: int):
252
+ if isinstance(self.table_locator, Table) and self.controller:
253
+ self.send(
254
+ TableOperation.MOVE_ROW.value.format(
255
+ register=self.table_locator.register,
256
+ table_name=self.table_locator.name,
257
+ from_row=from_row,
258
+ to_row=to_row,
259
+ )
260
+ )
230
261
  else:
231
- return Err("No rows could be read.")
262
+ raise ValueError("controller is offline or given device, need table")
232
263
 
233
- def move_row(self, from_row: int, to_row: int):
234
- self.send(
235
- TableOperation.MOVE_ROW.value.format(
236
- register=self.table_locator.register,
237
- table_name=self.table_locator.name,
238
- from_row=from_row,
239
- to_row=to_row,
264
+ def _read_str_param(self, register_flag: RegisterFlag):
265
+ if self.controller:
266
+ try:
267
+ return self.controller.get_text_val(
268
+ cmd=TableOperation.GET_OBJ_HDR_TEXT.value.format(
269
+ register=self.table_locator.register,
270
+ register_flag=register_flag,
271
+ )
272
+ )
273
+ except RuntimeError:
274
+ return self.controller.get_text_val(
275
+ cmd=TableOperation.GET_OBJ_HDR_TEXT.value.format(
276
+ register=self.table_locator.register + "[2]",
277
+ register_flag=register_flag,
278
+ )
279
+ )
280
+ raise ValueError("Communication controller is not online!")
281
+
282
+ def _read_num_param(self, register_flag: RegisterFlag):
283
+ if self.controller:
284
+ return self.controller.get_num_val(
285
+ cmd=TableOperation.GET_OBJ_HDR_VAL.value.format(
286
+ register=self.table_locator.register,
287
+ register_flag=register_flag,
288
+ )
240
289
  )
290
+ raise ValueError("Communication controller is not online!")
291
+
292
+ def _update_param(
293
+ self, param: Param, register_num: Optional[int] = None, sleep: bool = True
294
+ ):
295
+ register = self.table_locator.register
296
+ setting_command = (
297
+ TableOperation.UPDATE_OBJ_HDR_VAL
298
+ if param.ptype == PType.NUM
299
+ else TableOperation.UPDATE_OBJ_HDR_TEXT
241
300
  )
301
+ send_method: Callable = self.sleepy_send if sleep else self.send
302
+ if isinstance(param.chemstation_key, list):
303
+ for register_flag in param.chemstation_key:
304
+ send_method(
305
+ setting_command.value.format(
306
+ register=f"{register}[{str(register_num)}]"
307
+ if register_num
308
+ else register,
309
+ register_flag=register_flag,
310
+ val=param.val,
311
+ )
312
+ )
313
+ else:
314
+ register_flag = param.chemstation_key
315
+ send_method(
316
+ setting_command.value.format(
317
+ register=f"{register}[{str(register_num)}]"
318
+ if register_num
319
+ else register,
320
+ register_flag=register_flag,
321
+ val=param.val,
322
+ )
323
+ )
324
+ self.download()
@@ -1,7 +1,73 @@
1
1
  from dataclasses import dataclass
2
+ from enum import Enum
3
+ from typing import Optional
2
4
 
3
5
 
4
6
  @dataclass
7
+ class DADChannels:
8
+ A: int
9
+ A_ON: bool
10
+ B: int
11
+ B_ON: bool
12
+ C: int
13
+ C_ON: bool
14
+ D: int
15
+ D_ON: bool
16
+ E: int
17
+ E_ON: bool
18
+
19
+
20
+ class DADChannel(Enum):
21
+ A = "A"
22
+ B = "B"
23
+ C = "C"
24
+ D = "D"
25
+ E = "E"
26
+
27
+
28
+ class PumpPosition(Enum):
29
+ ONE = 1
30
+ TWO = 2
31
+
32
+ @classmethod
33
+ def from_str(cls, pos):
34
+ match pos:
35
+ case "Position1":
36
+ return PumpPosition.ONE
37
+ case "Position2":
38
+ return PumpPosition.TWO
39
+ case _:
40
+ raise ValueError("Expected one of Position 1 or Position 2")
41
+
42
+ def to_str(self):
43
+ match self:
44
+ case PumpPosition.ONE:
45
+ return "Position1"
46
+ case PumpPosition.TWO:
47
+ return "Position2"
48
+ case _:
49
+ raise ValueError("Enum is one of ONE or TWO")
50
+
51
+
52
+ class PumpValve(Enum):
53
+ A = "A"
54
+ B = "B"
55
+
56
+
57
+ @dataclass
58
+ class SolventBottle:
59
+ absolute_filled: float
60
+ percent_filled: float
61
+ type: Optional[PumpValve]
62
+ in_use: bool
63
+ user_name: str
64
+ max_volume: Optional[float]
65
+
66
+
67
+ MaybeBottle = Optional[SolventBottle]
68
+ MaybePumpPosition = Optional[PumpPosition]
69
+
70
+
5
71
  class SignalRead:
6
72
  on: bool
7
73
  wavelength: int
@@ -33,6 +33,8 @@ class Command(Enum):
33
33
  LAMP_OFF_CMD = "LampAll OFF"
34
34
  PUMP_ON_CMD = "PumpAll ON"
35
35
  PUMP_OFF_CMD = "PumpAll OFF"
36
+ COLUMN_ON_CMD = "ColumnAll ON"
37
+ COLUMN_OFF_CMD = "ColumnAll OFF"
36
38
  INSTRUMENT_OFF = 'macro "SHUTDOWN.MAC" ,go'
37
39
  INSTRUMENT_ON = 'LIDoOperation "TURN_ON"'
38
40