pytweezer.servers.device_status module

Device-server status service.

The server PC runs DeviceStatusServer, which periodically probes every device RPC server listed in CONFIG["Devices"] — regardless of which PC it runs on — and publishes an aggregate up/down snapshot over a ZMQ PUB socket. Client GUIs subscribe with DeviceStatusClient and display the result, so any machine can see the global device picture (not just its own devices).

This is a pull model: only the server PC probes, and it needs no cooperation from the device servers or the client GUIs beyond the config they already share.

A composite device serves several sub-devices from one port, and any of them may be missing while the rest run (see device_server._make_composite), so a TCP probe of that port is not enough to tell whether a given sub-device is up. Composites therefore get a second, RPC-level probe: a sipyco handshake returns the target names the server is actually serving, and each sub-device is reported individually under its own name — flat in the same devices dict as top-level devices, since device names are unique across the whole category. Sub-device entries carry "parent"; a composite’s entry carries "children".

class pytweezer.servers.device_status.DeviceStatusClient(host=None, pub_port=None, poll_interval_ms=200, parent=None)[source]

Bases: QObject

Subscribes to the device-status feed and emits the latest device dict.

Mirrors model_sync._ModelSyncClient: a non-blocking QTimer drains the SUB socket and re-emits the newest snapshot’s devices payload.

close()[source]
status_received

Emitted with the newest snapshot’s devices dict on each poll.

class pytweezer.servers.device_status.DeviceStatusServer(host=None, pub_port=None, poll_interval=None, probe_timeout=0.3)[source]

Bases: object

Polls every CONFIG["Devices"] server and publishes up/down snapshots.

Composites are probed twice: a TCP reachability check for the process, then an RPC handshake for the targets it serves, so each sub-device gets its own entry.

build_snapshot()[source]

Probe every device once and return the publishable snapshot dict.

A composite contributes one entry per sub-device as well as its own, all keyed by device name in the same flat dict.

serve_forever()[source]
stop()[source]
pytweezer.servers.device_status.main()[source]
pytweezer.servers.device_status.server_targets(host, port, timeout=1.0)[source]

Return the set of RPC target names a sipyco server serves, or None.

None means the question could not be answered — the server is unreachable, too busy to complete the handshake, or not a sipyco server at all — as opposed to an empty set, which means it is serving nothing.

Connects with target_name=None so no target is selected: the handshake alone carries the target list, and no RPC method is ever invoked.