Python controller reference
Every parameter, return value, and error of the Python controller that runs control sequences.
client.control.acquire returns a Controller. For a guided example, see
write a control sequence in Python. For how
writers share a channel, see control authority.
A channel argument is a channel name or key. All exception classes are in the synnax
module. A method that writes raises a ValidationError when write is empty. A method
that reads raises a ValidationError when read is empty.
Acquire a controller
acquire
client.control.acquire(name, read, write, write_authorities=255) -> ControllernamestrRequiredIdentifies the controller to other writers, such as in a schematic control legend.
readchannels or NoneRequiredOne channel or a list of channels to stream, or
None. The controller drops channels that do not exist, with no error.writechannels or NoneRequiredOne channel or a list of channels to command, or
None. The controller also writes their index channels.write_authoritiesint or list[int] = 255The authority on every
writechannel. Pass one value. For a different authority on each channel, callset_authorityafteracquire.
acquire opens a writer on the write channels at once, so it can take control of
them. It returns after the stream on the read channels is open.
Use the controller in a with block. Leaving the block calls release.
Write values
set
ctrl.set(channel, value) -> None
ctrl.set({channel: value, ...}) -> Nonechannelstr, int, or dictRequiredOne channel, or a dictionary of channels to values.
valuenumber, bool, or str = NoneThe value for one channel. Leave it out with a dictionary.
For each channel that has an index channel, set also writes the current time to the
index. A dictionary sends every value in one write. Values are converted to the data
type of the channel. If a different writer controls a channel, Synnax drops the value
and set raises no error.
The Core reports a write error after set returns. The next set raises the error, and
the controller cannot write again.
__setitem__
ctrl[channel] = valueThe same as ctrl.set(channel, value).
Attribute assignment also writes: ctrl.press_vlv_cmd = 1 is the same as
ctrl["press_vlv_cmd"] = 1. Use brackets for channel names that start with _, are not
valid Python names, or match a controller member such as state or set.
set_authority
ctrl.set_authority(authority) -> None
ctrl.set_authority(channel, authority) -> None
ctrl.set_authority({channel: authority, ...}) -> NoneAn int with no authority is always an authority, not a channel key. Channels that
share an index channel share its authority, and the index channel decides for its data
channels. See how authority works.
Read values
The controller keeps the latest numeric value of each read channel: the last sample of
the most recent frame. Values of string and json channels are not kept.
__getitem__
ctrl[channel] -> int | float | numpy.numberReturns the latest value of the channel. Attribute access also works: ctrl.tank_pt is
the same as ctrl["tank_pt"]. Attribute access fails for a channel whose name is not a
valid Python name, or matches a controller member such as state, set, get,
sleep, or release.
get
ctrl.get(channel, default=None) -> int | float | numpy.number | NoneReturns the latest value of the channel. Returns default if no value arrived yet or
the channel is not in read. Raises NotFoundError if the channel does not exist.
state
ctrl.state -> dict[int, int | float | numpy.number]The latest value of each read channel that has a value, by channel key. Channels with
no value yet are not in the dictionary.
Wait for conditions
A condition is a function that takes the controller and returns a bool, such as
lambda c: c["tank_pt"] > 300. The controller calls it each time a frame arrives on a
read channel, not at once. An exception that the condition raises, such as a
KeyError from a channel with no value, stops the wait and is raised again. Do not call
a wait method inside a condition: the controller deadlocks.
Each wait method raises a ValueError if cond is not callable. If the stream fails,
the wait raises that error instead of waiting for the timeout. An unexpected stream
closure raises UnexpectedError.
wait_until
ctrl.wait_until(cond, timeout=None) -> boolcondCallable[[Controller], bool]RequiredThe condition.
timeoutCrudeTimeSpan or None = NoneA number of seconds, a
datetime.timedelta, or aTimeSpan.Noneor0waits forever.
Returns True when cond returns true, or False when the timeout ends first.
wait_while
ctrl.wait_while(cond, timeout=None) -> boolTakes the same parameters as wait_until. Returns True when cond returns false, or
False when the timeout ends first.
wait_until_defined
ctrl.wait_until_defined(channels, timeout=None) -> boolBlocks until each channel in channels has a value. channels is one channel or a
list. Returns False when the timeout ends first. A channel that is not in read never
gets a value, so the call blocks until the timeout, or forever. Raises NotFoundError
if a channel does not exist.
remains_true_for
ctrl.remains_true_for(cond, duration, percentage=1) -> boolcondCallable[[Controller], bool]RequiredThe condition.
durationCrudeTimeSpanRequiredHow long to check: a number of seconds, a
TimeSpan, or adatetime.timedelta. For example,10and10 * sy.TimeSpan.SECONDboth mean ten seconds.percentagefloat = 1The fraction of frames, from 0 to 1, for which
condmust return true.
Blocks for up to duration. Returns True if cond returned true for at least
percentage of the frames that arrived. Returns False if no frame arrived.
sleep
ctrl.sleep(dur, precise=False) -> NoneBlocks for dur, a number of seconds or a TimeSpan. Set precise=True for
millisecond accuracy. A precise sleep uses more CPU.
Release control
release
ctrl.release() -> NoneCloses the writer and stops the stream. Control of each write channel passes to the
writer with the next highest authority. Channel values do not change. Do not use the
controller after release. Leaving a with block calls release, also after an
exception. Raises the error that closed the writer, if the Core closed it with one.
Schedule commands
schedule
ctrl.schedule(*commands: ScheduledCommand) -> tuple[Callable[[], None], bool]Returns a function and True. Call the function to run the commands in order: for each
command, it sleeps for delay with a precise sleep, then sets the value. schedule
itself sends nothing.
ScheduledCommand(channel, value, delay) is in synnax.control. Each delay counts
from the previous command. A number for delay is in seconds. A TimeSpan also works.
Retrieve control state
retrieve
client.control.retrieve(*, name=None, key=None, names=None, keys=None)
-> State | list[State] | NoneReturns which writer controls channels. Pass parameters by name. It does not need a controller.
A State has subject.name and subject.key (the writer), resource (the channel
key), and authority. Raises NotFoundError if the channel given by name or key
does not exist. names= drops names that do not exist, with no error.