Use softioc.autosave in an IOC
Creating an IOC shows how to create a pythonSoftIOC.
Example IOC
from softioc import autosave, builder, softioc
import cothread
# Set the record prefix
builder.SetDeviceName("MY-DEVICE-PREFIX")
# Create records, set some of them to autosave, also save some of their fields
builder.aOut("AO", autosave=True)
builder.aIn("AI", autosave=["PREC", "EGU"])
builder.boolIn("BO")
builder.WaveformIn("WAVEFORMIN", [0, 0, 0, 0], autosave=True)
with autosave.Autosave(["VAL", "LOPR", "HOPR"]):
builder.aOut("AUTOMATIC-AO", autosave=["EGU"])
seconds = builder.longOut("SECONDSRUN", autosave=True)
autosave.configure(
directory="/tmp/autosave-data",
name="MY-DEVICE-PREFIX",
save_period=5.0
)
builder.LoadDatabase()
softioc.iocInit()
# Start processes required to be run after iocInit
def update():
while True:
cothread.Sleep(1)
seconds.set(seconds.get() + 1)
cothread.Spawn(update)
softioc.interactive_ioc(globals())
Records are instantiated as normal and configured for automatic loading and
periodic saving to a backup file with use of the keyword argument autosave.
autosave resolves to a list of strings, which are the names of fields to be
tracked by autosave. By default autosave=False, which disables autosave for that PV.
Setting autosave=True is equivalent to passing ["VAL"]. Note that "VAL" must be
explicitly passed when tracking other fields, e.g. ["VAL", "LOPR", "HOPR"].
autosave can also accept a single string field name as an argument.
The field values get written into a yaml-formatted file containing key-value pairs.
By default the keys are the same as the full PV name, including any device name specified
in SetDeviceName().
Autosave is disabled until configure() is called. The first two arguments,
directory and name are required. Backup files are periodically written into
directory with the name <name>.softsav every save_period seconds,
set to 30.0 by default. The directory must exist, and should be configured with the appropriate
read/write permissions for the user running the IOC.
IOC developers should only need to interface with autosave via the configure()
method and the autosave keyword argument. Alternatively,
PVs can be instantiated inside the Autosave() context manager, which
automatically passes the autosave argument to any PVs created
inside the context manager. If any fields are already specified by the autosave keyword
argument of a PV’s initialisation call the lists of fields to track get combined.
All other module members are intended for internal use only.
In normal operation, loading from a backup is performed once during the
LoadDatabase() call and periodic saving to the backup file begins when
iocInit() is called, provided that any PVs are configured to be saved.
Currently, manual loading from a backup at runtime after ioc initialisation is not supported.
Saving only occurs when any of the saved field values have changed since the last save.
Users are discouraged from manually editing the backup files while the
IOC is running so that the internal state of the autosave thread is consistent with
the backup file.
If autosave is enabled and active, a timestamped copy of the latest existing autosave backup file is created
when the IOC is restarted, e.g. <name>.softsav_240717-095004 (timestamps are in the format yymmdd-HHMMSS).
If you only wish to store one backup of the autosave file at a time, timestamped_backups=False
can be passed to configure() when it is called, this will create a backup file
named <name>.softsav.bu. To disable any autosaving, comment out the
configure() call or pass it the keyword argument
enabled=False.
The resulting backup file after running the example IOC for about 30 seconds is the following:
MY-DEVICE-PREFIX:AI.EGU: ''
MY-DEVICE-PREFIX:AI.PREC: '0'
MY-DEVICE-PREFIX:AO: 0.0
MY-DEVICE-PREFIX:AUTOMATIC-AO: 0.0
MY-DEVICE-PREFIX:AUTOMATIC-AO.EGU: ''
MY-DEVICE-PREFIX:AUTOMATIC-AO.HOPR: '0'
MY-DEVICE-PREFIX:AUTOMATIC-AO.LOPR: '0'
MY-DEVICE-PREFIX:SECONDSRUN: 29
MY-DEVICE-PREFIX:WAVEFORMIN: [0, 0, 0, 0]
If the IOC is stopped and restarted, the SECONDSRUN record will load its saved value of 29 from the backup. All non-VAL fields are stored as strings. Waveform type records holding arrays are cast into lists before saving.
This example IOC uses cothread, but autosave works identically when using an asyncio dispatcher.