|
6 | 6 |
|
7 | 7 | .. autosummary:: |
8 | 8 | |
| 9 | + ~ApsCycleComputedRO |
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,23 @@ def use_EPICS_scaler_channels(scaler): |
174 | 176 | scaler.channels.configuration_attrs = configuration_attrs |
175 | 177 |
|
176 | 178 |
|
| 179 | +class ApsCycleComputedRO(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 | + This signal is read-only. |
| 188 | + """ |
| 189 | + |
| 190 | + def get(self): |
| 191 | + dt = datetime.now() |
| 192 | + aps_cycle = f"{dt.year}-{int((dt.month-0.1)/4) + 1}" |
| 193 | + return aps_cycle |
| 194 | + |
| 195 | + |
177 | 196 | class ApsOperatorMessagesDevice(Device): |
178 | 197 | """general messages from the APS main control room""" |
179 | 198 | operators = Component(EpicsSignalRO, "OPS:message1", string=True) |
@@ -218,6 +237,7 @@ class ApsMachineParametersDevice(Device): |
218 | 237 | """ |
219 | 238 | current = Component(EpicsSignalRO, "S:SRcurrentAI") |
220 | 239 | lifetime = Component(EpicsSignalRO, "S:SRlifeTimeHrsCC") |
| 240 | + aps_cycle = Component(ApsCycleComputedRO) |
221 | 241 | machine_status = Component(EpicsSignalRO, "S:DesiredMode", string=True) |
222 | 242 | # In [3]: APS.machine_status.enum_strs |
223 | 243 | # Out[3]: |
|
0 commit comments