plesty.lib.service.tcp_ip_client

ZeroMQ-based TCP/IP client for remote device control.

Attributes

DISCONNECT_TIMEOUT_S

Classes

DeviceTCPIPClient

ZeroMQ-based client for remote device control.

Module Contents

plesty.lib.service.tcp_ip_client.DISCONNECT_TIMEOUT_S = 30.0
class plesty.lib.service.tcp_ip_client.DeviceTCPIPClient(address='tcp://localhost:5555', timeout=5000, resources=None, client_id: str | None = None, connect_kwargs: dict | None = None)

ZeroMQ-based client for remote device control.

This client provides a transparent interface to a remote device server. Methods can be invoked as if the device were local.

The server address it was opened with stays available as address.

Features:
  • Standard query/write interface

  • Arbitrary remote function calls

  • Automatic method discovery and binding

  • Timeout support

  • Structured error handling

Initialize the device client.

Parameters:
  • address – Server address.

  • timeout – Receive timeout in milliseconds.

  • resources – Resource request as a string, flat collection, or nested dict tree.

  • client_id (str | None) – Optional stable client identity for server-side routing.

  • connect_kwargs (dict | None) – Optional metadata sent during connect handshake.

ctx
socket
client_id = 'client-00000000000000000000000000000000'
address = 'tcp://localhost:5555'
resources
connect_kwargs
default_timeout = 5000
response_grace_ms = 1000
_connected = False
connection_info = None
_budgets: dict[str, float]
set_default_timeout(timeout_ms: int) → None

Change the receive timeout used by requests without their own.

Parameters:

timeout_ms (int) – New default receive timeout in milliseconds.

Return type:

None

connect() → None

Connect to the server, discover methods, and bind them locally.

Return type:

None

_close_socket() → None

Close the socket and context without waiting for undelivered messages.

The handshake to an absent server sits in the DEALER’s queue forever; with the default infinite LINGER, ctx.term() then blocks forever too — a connect to a dead server never returned, and no deadline could bound it. Linger 0 drops what could not be delivered.

Return type:

None

_send(payload)

Send a request to the server and wait for response.

Parameters:

payload – Dictionary payload.

Returns:

Result from server.

Return type:

Any

Raises:
  • RuntimeError – If server returns an error.

  • TimeoutError – If no response is received.

connect_to_server() → Any

Send a handshake so the server can register client metadata.

Return type:

Any

disconnect_from_server() → Any

Release server-side allocations, and wait for the server to confirm.

Given its own generous window rather than the client default: the device runs calls on one thread, so a disconnect arriving behind a long operation waits for that operation first. On the client default it timed out, the socket closed, and the server’s confirmation went nowhere — leaving the allocations held and the log unable to distinguish a clean exit from a client that vanished.

Raises:

TimeoutError – If the server does not confirm in time. The client is marked disconnected either way; the caller decides whether to care, and close() logs and carries on.

Return type:

Any

_resolve_recv_timeout_ms(payload_timeout_s)

Convert per-request operation timeout (seconds) into socket receive timeout (ms).

A small grace window is added so the client still receives timeout/error responses sent by the server right after operation timeout is reached.

query(param: Any, timeout: Any = None) → Any

Query a device parameter.

Parameters:
  • param (Any) – Parameter name.

  • timeout (Any) – Optional timeout in seconds (server-side).

Returns:

Parameter value.

Return type:

Any

write(param: Any, value: Any, timeout: Any = None) → Any

Write a device parameter.

Parameters:
  • param (Any) – Parameter name.

  • value (Any) – Value to set.

  • timeout (Any) – Optional timeout in seconds (server-side).

Returns:

Result from device.

Return type:

Any

call(func: Any, *args: Any, timeout: Any = None, **kwargs: Any) → Any

Call a remote device function.

An operation that declared a budget through describe is waited for that long unless the caller passes a timeout of its own. This is where the budget is applied rather than in the bound proxy, because this is the one funnel every call goes through: anything invoking an operation by name — the client field test, a caller working from a method list — never touches the proxy, and applying it there only left those on the client default.

Parameters:
  • func (Any) – Function name.

  • args (Any) – Positional arguments.

  • timeout (Any) – Optional timeout in seconds (server-side). Overrides the operation’s declared budget.

  • kwargs (Any) – Keyword arguments.

Returns:

Function result.

Return type:

Any

describe() → dict[str, Any]

Retrieve available device methods from server.

Returns:

Device description.

Return type:

dict

close() → None

Release server-side allocations, then close local ZMQ resources.

The socket is not torn down until the server has confirmed the disconnect, or until DISCONNECT_TIMEOUT_S has passed with no answer. Closing first leaves the server holding this client’s allocations and writing its reply to an identity that no longer exists — the “answer lost, the operation still ran” case, which looks in the log exactly like a client that crashed.

The wait is bounded rather than open-ended: a server that has died will never answer, and close() must still return.

Return type:

None

__enter__()

Enter the client context manager.

__exit__(exc_type, exc_value, traceback)

Exit the client context manager, closing the connection.

_build_methods()

Dynamically attach remote methods as local methods.

_make_proxy(name)

Create a proxy method for a remote function.

The declared budget is applied by call(), which this goes through, so a proxied call and a call by name wait the same length of time.

Parameters:

name – Function name.

Returns:

Proxy method.

Return type:

callable