PLESTY devices run as ZMQ REQ/REP servers. Any number of clients — experiments, analyzers, or interactive scripts — can connect from the same machine or over the network.
Communication model
Starting a server
import asyncio
from plesty.power_meter import PowermeterDevice
from plesty.lib.service import build_server
async def main() -> None:
device = PowermeterDevice("USB0::0x1313::0x8078::P0000001::INSTR", sensor_type="S155C")
server = build_server(device, fixed_threading=False, address="tcp://*:5555")
await server.run()
asyncio.run(main())
build_server signature:
def build_server(
device: Any,
fixed_threading: bool = False,
address: str = "tcp://*:5555",
) -> DeviceTCPIPServer:
| Parameter | Default | Effect |
|---|---|---|
device |
required | Synchronous device instance |
fixed_threading |
False |
False → AsyncWrapperSafe (simple); True → AsyncDeviceThread (high-frequency) |
address |
"tcp://*:5555" |
ZMQ bind address — * binds all interfaces |
Connecting a client
from plesty.lib.service import build_client
client = build_client(address="tcp://192.168.1.10:5555", timeout=5000)
# Same API as the local device
wavelength = client.query("WAVELENGTH")
client.write("WAVELENGTH", 1064)
power = client.query("POWER")
build_client signature:
def build_client(
address: str = "tcp://localhost:5555",
timeout: int = 5000,
resources: Any = None,
client_id: str | None = None,
connect_kwargs: dict | None = None,
) -> DeviceTCPIPClient:
| Parameter | Default | Effect |
|---|---|---|
address |
"tcp://localhost:5555" |
Server address |
timeout |
5000 |
Receive timeout in milliseconds |
resources |
None |
Resources to reserve on connect (for shared devices) |
client_id |
None |
Stable client identity for resource tracking |
Protocol
The server uses ZMQ REQ/REP sockets with JSON message serialization. Each request carries the operation name, parameters, and optional resource list. The server dispatches through the async wrapper, executes on the device, and returns the result.
Tip: The client exposes the same
write,query,get_config_list,identity, and operation-call interface as the local device. Code that works with a local device instance works unmodified with a client.
Resource locking
When a device is shared by multiple clients (e.g., a multi-channel NI DAQ used by two experiments simultaneously), use the resources argument to reserve exclusive access:
client = build_client(
address="tcp://daq-host:5555",
resources=["Dev1/port0/line0", "Dev1/port0/line1"],
client_id="experiment-A",
)
A second client requesting the same resources will be rejected until the first client disconnects.