|
6 | 6 |
|
7 | 7 | .. autosummary:: |
8 | 8 | |
| 9 | + ~ApsCycleComputed |
9 | 10 | ~ApsMachineParametersDevice |
10 | 11 | ~ApsPssShutter |
11 | 12 | ~ApsPssShutterWithStatus |
|
129 | 130 | from ophyd import Signal, EpicsMotor, EpicsSignal, EpicsSignalRO |
130 | 131 | from ophyd.mca import EpicsMCARecord |
131 | 132 | from ophyd.scaler import EpicsScaler, ScalerCH |
| 133 | +from ophyd.sim import SignalRO |
132 | 134 |
|
133 | 135 | from ophyd.areadetector.filestore_mixins import FileStoreBase |
134 | 136 | from ophyd.areadetector.filestore_mixins import FileStorePluginBase |
@@ -174,6 +176,21 @@ def use_EPICS_scaler_channels(scaler): |
174 | 176 | scaler.channels.configuration_attrs = configuration_attrs |
175 | 177 |
|
176 | 178 |
|
| 179 | +class ApsCycleComputed(SignalRO): |
| 180 | + """ |
| 181 | + compute the APS cycle name based on the calendar and the usual practice |
| 182 | +
|
| 183 | + Absent any facility PV that provides the name of the current operating |
| 184 | + cycle, this can be approximated by python computation (as long as the |
| 185 | + present scheduling pattern is maintained) |
| 186 | + """ |
| 187 | + |
| 188 | + def get(self): |
| 189 | + dt = datetime.now() |
| 190 | + aps_cycle = f"{dt.year}-{int((dt.month-0.1)/4) + 1}" |
| 191 | + return aps_cycle |
| 192 | + |
| 193 | + |
177 | 194 | class ApsOperatorMessagesDevice(Device): |
178 | 195 | """general messages from the APS main control room""" |
179 | 196 | operators = Component(EpicsSignalRO, "OPS:message1", string=True) |
@@ -218,6 +235,7 @@ class ApsMachineParametersDevice(Device): |
218 | 235 | """ |
219 | 236 | current = Component(EpicsSignalRO, "S:SRcurrentAI") |
220 | 237 | lifetime = Component(EpicsSignalRO, "S:SRlifeTimeHrsCC") |
| 238 | + aps_cycle = Component(ApsCycleComputed) |
221 | 239 | machine_status = Component(EpicsSignalRO, "S:DesiredMode", string=True) |
222 | 240 | # In [3]: APS.machine_status.enum_strs |
223 | 241 | # Out[3]: |
|
0 commit comments