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.
- pychemstation/control/controllers/comm.py +1 -1
- pychemstation/control/controllers/data_aq/method.py +112 -136
- pychemstation/control/controllers/data_aq/sequence.py +49 -24
- pychemstation/control/controllers/devices/column.py +61 -0
- pychemstation/control/controllers/devices/dad.py +85 -0
- pychemstation/control/controllers/devices/injector.py +18 -0
- pychemstation/control/controllers/devices/pump.py +131 -0
- pychemstation/control/controllers/devices/sample_info.py +27 -0
- pychemstation/control/hplc.py +36 -12
- pychemstation/utils/abc_tables/device.py +17 -3
- pychemstation/utils/abc_tables/table.py +146 -63
- pychemstation/utils/device_types.py +66 -0
- pychemstation/utils/macro.py +2 -0
- pychemstation/utils/table_types.py +65 -8
- {pychemstation-0.10.11.dist-info → pychemstation-0.10.12.dist-info}/METADATA +2 -2
- {pychemstation-0.10.11.dist-info → pychemstation-0.10.12.dist-info}/RECORD +18 -14
- {pychemstation-0.10.11.dist-info → pychemstation-0.10.12.dist-info}/WHEEL +0 -0
- {pychemstation-0.10.11.dist-info → pychemstation-0.10.12.dist-info}/licenses/LICENSE +0 -0
@@ -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.")
|
pychemstation/control/hplc.py
CHANGED
@@ -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
|
13
|
-
from
|
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
|
-
|
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
|
-
|
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.
|
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.
|
343
|
+
self.method_controller.dad.turn_on()
|
320
344
|
|
321
345
|
def lamp_off(self):
|
322
346
|
"""Turns the UV lamp off."""
|
323
|
-
self.
|
347
|
+
self.method_controller.dad.turn_off()
|
324
348
|
|
325
349
|
def pump_on(self):
|
326
350
|
"""Turns on the pump on."""
|
327
|
-
self.
|
351
|
+
self.method_controller.pump.turn_on()
|
328
352
|
|
329
353
|
def pump_off(self):
|
330
354
|
"""Turns the pump off."""
|
331
|
-
self.
|
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.
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
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.
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
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.
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
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.
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
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.
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
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.
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
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(
|
247
|
+
raise ValueError(
|
248
|
+
"controller was offline or was given a device and not a table"
|
249
|
+
)
|
227
250
|
|
228
|
-
|
229
|
-
|
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
|
-
|
262
|
+
raise ValueError("controller is offline or given device, need table")
|
232
263
|
|
233
|
-
def
|
234
|
-
self.
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
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
|
pychemstation/utils/macro.py
CHANGED
@@ -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
|
|