plesty.server.services.control

The console’s connection to a running device server.

The console manages device servers; this is the one place it talks to one. A DeviceLink satisfies plesty-lib’s DeviceHandle — describe, query, write, call — so a DevicePanel built on it renders the controls the device declares, and the console needs no schema of its own.

Two things it does deliberately:

It connects on first use, not when it is made. DeviceTCPIPClient handshakes and describes inside its constructor, and a ZMQ socket belongs to the thread that created it. A panel runs its calls on a worker thread of its own, so building the client there — on the first describe — keeps the socket on one thread for its whole life, instead of making it on the console’s pool and migrating it.

It asks for no resources. The connection handshake can claim an allocation, and the device server enforces it. A console panel is a second client on a device an experiment may be driving: it takes nothing, so opening the controls can never be what makes a measurement fail. Writes are gated in the panel instead, behind Take control.

Attributes

DEVICE_TIMEOUT_MS

Classes

DeviceLink

A lazy DeviceHandle over one device server.

Module Contents

plesty.server.services.control.DEVICE_TIMEOUT_MS = 15000

A lazy DeviceHandle over one device server.

Prepare a link; nothing is connected yet.

Parameters:
  • name (str) – The device’s fleet name, for messages.

  • address (str) – ZMQ endpoint of its server, tcp://host:port.

  • timeout_ms (int) – Reply timeout for one call.

  • resolve (collections.abc.Callable[[], str | None] | None) – Returns where the server is now, or None when it is not running; raises when that is not known. A restarted server can come back on another port; a link that kept the first address drove a port nobody listened on, and the panel’s controls silently did nothing (#22).

name
address
timeout_ms = 15000
_resolve = None
_client: Any = None
_held = False
hold() → None

Refuse every call until release(): the server is being stopped.

A call sent to a server that is shutting down, or to the port it left, gets no reply and waits out the whole timeout — and every call after it waits behind it on the panel’s one worker. Restarting on a new port left the panel dead for up to fifteen seconds that way (#22). Held, a call fails at once and sends nothing.

Return type:

None

release() → None

Let calls through again after hold().

Return type:

None

_follow() → None

Move to the server’s current address, dropping a client on the old one.

Raises:

ConnectionError – When the server is not running, rather than send a call to an address nothing answers on.

Return type:

None

client() → Any

Return the connected client, building it on first use.

Returns:

The DeviceTCPIPClient.

Raises:

ConnectionError – When the link is held or the server is not running.

Return type:

Any

describe() → dict[str, Any]

Return the device’s methods and its serialized doc model.

Return type:

dict[str, Any]

query(key: str) → Any

Read configuration parameter key.

Parameters:

key (str)

Return type:

Any

write(key: str, value: Any) → Any

Write value to configuration parameter key.

Parameters:
  • key (str)

  • value (Any)

Return type:

Any

call(op: str, **kwargs: Any) → Any

Run operation op.

Parameters:
  • op (str)

  • kwargs (Any)

Return type:

Any

close() → None

Release the connection; a later call reconnects.

Never raises: this runs when a panel closes and a window is going away, and a server that already died must not be what stops it.

Return type:

None