Skip to content

Commit 440b816

Browse files
Tidy up allvalvescontrol (#1058)
* Tidy up allvalvescontrol * Simplify with Generics --------- Co-authored-by: Joseph Ware <[email protected]>
1 parent 321c785 commit 440b816

File tree

2 files changed

+242
-148
lines changed

2 files changed

+242
-148
lines changed

src/dodal/devices/pressure_jump_cell.py

Lines changed: 56 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import asyncio
2-
from dataclasses import dataclass
2+
from typing import Generic, TypeVar
33

44
from bluesky.protocols import HasName, Movable
55
from ophyd_async.core import (
@@ -26,18 +26,18 @@ class StopState(StrictEnum):
2626
STOP = "STOP"
2727

2828

29-
class FastValveControlRequest(StrictEnum):
29+
class ValveControlRequest(StrictEnum):
3030
OPEN = "Open"
3131
CLOSE = "Close"
3232
RESET = "Reset"
33-
ARM = "Arm"
34-
DISARM = "Disarm"
3533

3634

37-
class ValveControlRequest(StrictEnum):
38-
OPEN = "Open"
39-
CLOSE = "Close"
40-
RESET = "Reset"
35+
class FastValveControlRequest(StrictEnum):
36+
OPEN = ValveControlRequest.OPEN.value
37+
CLOSE = ValveControlRequest.CLOSE.value
38+
RESET = ValveControlRequest.RESET.value
39+
ARM = "Arm"
40+
DISARM = "Disarm"
4141

4242

4343
class ValveOpenSeqRequest(StrictEnum):
@@ -60,138 +60,89 @@ class ValveState(StrictEnum):
6060

6161

6262
class FastValveState(StrictEnum):
63-
FAULT = "Fault"
64-
OPEN = "Open"
63+
FAULT = ValveState.FAULT.value
64+
OPEN = ValveState.OPEN.value
6565
OPEN_ARMED = "Open Armed"
66-
CLOSED = "Closed"
66+
CLOSED = ValveState.CLOSED.value
6767
CLOSED_ARMED = "Closed Armed"
6868
NONE = "Unused"
6969

7070

71-
@dataclass
72-
class AllValvesControlState:
73-
valve_1: ValveControlRequest | None = None
74-
valve_3: ValveControlRequest | None = None
75-
valve_5: FastValveControlRequest | None = None
76-
valve_6: FastValveControlRequest | None = None
71+
TValveControlRequest = TypeVar(
72+
"TValveControlRequest", bound=ValveControlRequest | FastValveControlRequest
73+
)
74+
7775

76+
class ValveControl(
77+
StandardReadable, Movable[TValveControlRequest], Generic[TValveControlRequest]
78+
):
79+
def __init__(
80+
self,
81+
prefix: str,
82+
valve_control_type: type[TValveControlRequest],
83+
name: str = "",
84+
):
85+
with self.add_children_as_readables():
86+
self.control = epics_signal_rw(valve_control_type, prefix + ":CON")
87+
self.open = epics_signal_rw(int, prefix + ":OPENSEQ")
88+
super().__init__(name)
7889

79-
class AllValvesControl(StandardReadable, Movable[AllValvesControlState]):
90+
@AsyncStatus.wrap
91+
async def set(self, value: TValveControlRequest):
92+
if value.value == "Open":
93+
await self.open.set(ValveOpenSeqRequest.OPEN_SEQ.value)
94+
await asyncio.sleep(OPENSEQ_PULSE_LENGTH)
95+
await self.open.set(ValveOpenSeqRequest.INACTIVE.value)
96+
else:
97+
await self.control.set(value)
98+
99+
100+
class AllValvesControl(StandardReadable):
80101
"""
81-
valves 2, 4, 7, 8 are not controlled by the IOC,
82-
as they are under manual control.
83-
fast_valves: tuple[int, ...] = (5, 6)
84-
slow_valves: tuple[int, ...] = (1, 3)
102+
The default IOC for this device only controls
103+
specific valves. Other valves are under manual
104+
control.
85105
"""
86106

87107
def __init__(
88108
self,
89109
prefix: str,
90110
name: str = "",
91-
fast_valves: tuple[int, ...] = (5, 6),
92-
slow_valves: tuple[int, ...] = (1, 3),
111+
fast_valves_numbers: tuple[int, ...] = (5, 6),
112+
slow_valves_numbers: tuple[int, ...] = (1, 3),
93113
) -> None:
94-
self.fast_valves = fast_valves
95-
self.slow_valves = slow_valves
96114
with self.add_children_as_readables():
97115
self.valve_states: DeviceVector[SignalR[ValveState]] = DeviceVector(
98116
{
99117
i: epics_signal_r(ValveState, f"{prefix}V{i}:STA")
100-
for i in self.slow_valves
118+
for i in slow_valves_numbers
101119
}
102120
)
103121
self.fast_valve_states: DeviceVector[SignalR[FastValveState]] = (
104122
DeviceVector(
105123
{
106124
i: epics_signal_r(FastValveState, f"{prefix}V{i}:STA")
107-
for i in self.fast_valves
125+
for i in fast_valves_numbers
108126
}
109127
)
110128
)
111129

112-
self.fast_valve_control: DeviceVector[FastValveControl] = DeviceVector(
113-
{i: FastValveControl(f"{prefix}V{i}") for i in self.fast_valves}
114-
)
130+
self.fast_valve_control = {
131+
i: ValveControl(f"{prefix}V{i}", FastValveControlRequest)
132+
for i in fast_valves_numbers
133+
}
115134

116-
self.valve_control: DeviceVector[ValveControl] = DeviceVector(
117-
{i: ValveControl(f"{prefix}V{i}") for i in self.slow_valves}
118-
)
119-
120-
super().__init__(name)
135+
self.slow_valve_control = {
136+
i: ValveControl(f"{prefix}V{i}", ValveControlRequest)
137+
for i in slow_valves_numbers
138+
}
121139

122-
async def set_valve(
123-
self,
124-
valve: int,
125-
value: ValveControlRequest | FastValveControlRequest,
126-
):
127-
if valve in self.slow_valves and (isinstance(value, ValveControlRequest)):
128-
if value == ValveControlRequest.OPEN:
129-
await self.valve_control[valve].set(ValveOpenSeqRequest.OPEN_SEQ)
130-
await asyncio.sleep(OPENSEQ_PULSE_LENGTH)
131-
await self.valve_control[valve].set(ValveOpenSeqRequest.INACTIVE)
132-
else:
133-
await self.valve_control[valve].set(value)
134-
135-
elif valve in self.fast_valves and (isinstance(value, FastValveControlRequest)):
136-
if value == FastValveControlRequest.OPEN:
137-
await self.fast_valve_control[valve].set(ValveOpenSeqRequest.OPEN_SEQ)
138-
await asyncio.sleep(OPENSEQ_PULSE_LENGTH)
139-
await self.fast_valve_control[valve].set(ValveOpenSeqRequest.INACTIVE)
140-
else:
141-
await self.fast_valve_control[valve].set(value)
140+
all_valves = self.fast_valve_control | self.slow_valve_control
142141

143-
@AsyncStatus.wrap
144-
async def set(self, value: AllValvesControlState):
145-
await asyncio.gather(
146-
*(
147-
self.set_valve(int(i[-1]), value)
148-
for i, value in value.__dict__.items()
149-
if value is not None
150-
)
151-
)
152-
153-
154-
class ValveControl(
155-
StandardReadable, Movable[ValveControlRequest | ValveOpenSeqRequest]
156-
):
157-
def __init__(self, prefix: str, name: str = "") -> None:
158-
with self.add_children_as_readables():
159-
self.close = epics_signal_rw(ValveControlRequest, prefix + ":CON")
160-
self.open = epics_signal_rw(int, prefix + ":OPENSEQ")
142+
self.valve_control: DeviceVector[ValveControl] = DeviceVector(all_valves)
161143

162144
super().__init__(name)
163145

164-
def set(self, value: ValveControlRequest | ValveOpenSeqRequest) -> AsyncStatus:
165-
set_status = None
166-
167-
if isinstance(value, ValveControlRequest):
168-
set_status = self.close.set(value)
169-
elif isinstance(value, ValveOpenSeqRequest):
170-
set_status = self.open.set(value.value)
171-
172-
return set_status
173-
174-
175-
class FastValveControl(
176-
StandardReadable, Movable[FastValveControlRequest | ValveOpenSeqRequest]
177-
):
178-
def __init__(self, prefix: str, name: str = "") -> None:
179-
with self.add_children_as_readables():
180-
self.close = epics_signal_rw(FastValveControlRequest, prefix + ":CON")
181-
self.open = epics_signal_rw(int, prefix + ":OPENSEQ")
182-
183-
super().__init__(name)
184-
185-
def set(self, value: FastValveControlRequest | ValveOpenSeqRequest) -> AsyncStatus:
186-
set_status = None
187-
188-
if isinstance(value, FastValveControlRequest):
189-
set_status = self.close.set(value)
190-
elif isinstance(value, ValveOpenSeqRequest):
191-
set_status = self.open.set(value.value)
192-
193-
return set_status
194-
195146

196147
class Pump(StandardReadable):
197148
def __init__(self, prefix: str, name: str = "") -> None:

0 commit comments

Comments
 (0)