Plesty Documentation

TCP/IP Communication

How devices expose themselves as ZMQ TCP servers and how clients connect from experiments and analyzers.

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

Device Server
Host machine (instrument connected)
tcp://*:5555
Wraps sync device in async loop
REQ →
← REP
Experiment Client
build_client("tcp://host:5555")
Analyzer Client
build_client("tcp://host:5555")

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 FalseAsyncWrapperSafe (simple); TrueAsyncDeviceThread (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.