Skip to content

deck server/client over a remote API#896

Open
Koeng101 wants to merge 2 commits intoPyLabRobot:mainfrom
Koeng101:deckProto
Open

deck server/client over a remote API#896
Koeng101 wants to merge 2 commits intoPyLabRobot:mainfrom
Koeng101:deckProto

Conversation

@Koeng101
Copy link

This PR adds a remote backend for the deck. This can be shared across many instances.

# server.py
import uvicorn
from pylabrobot.resources import Cor_96_wellplate_360ul_Fb, hamilton_96_tiprack_1000uL_filter
from pylabrobot.resources.hamilton import STARDeck
from pylabrobot.resources.remote.server import create_app

deck = STARDeck()
deck.assign_child_resource(hamilton_96_tiprack_1000uL_filter(name="tips"), rails=3)
deck.assign_child_resource(Cor_96_wellplate_360ul_Fb(name="plate"), rails=9)

app = create_app(deck)
uvicorn.run(app, host="0.0.0.0", port=8080)
# client.py
import asyncio
from pylabrobot.liquid_handling import LiquidHandler
from pylabrobot.liquid_handling.backends import STARBackend
from pylabrobot.resources.remote.client import RemoteDeck

deck = RemoteDeck.connect("http://localhost:8080")
lh = LiquidHandler(backend=STARBackend(), deck=deck)
await lh.setup()

tips = deck.get_resource("tips")
plate = deck.get_resource("plate")
await lh.pick_up_tips(tips["A1:H1"])
await lh.aspirate(plate["A1:H1"], vols=[100.0] * 8)
await lh.dispense(plate["A2:H2"], vols=[100.0] * 8)
await lh.drop_tips(tips["A1:H1"])

The key difference is that the deck can now be accessed through a standard API. This can be just in-memory (as it is right now), but it is now trivial to add a custom backing - whether that be SQL or document store or JSON files or anything else.

The concept is that you can have a server directly connected to a robot controlling it, but have the resource model be on a centralized server for state management.

Koeng101 and others added 2 commits February 17, 2026 11:23
Serve a Deck's resource tree over HTTP so a LiquidHandler on another
machine (or process) can use it as a drop-in replacement. The server
wraps a real Deck and exposes 31 RPCs covering tree retrieval, spatial
queries, volume/tip tracker mutations, and structure changes. The
client (RemoteDeck) fetches the tree on connect and builds local proxy
objects that pass isinstance checks (WellProxy IS-A Well, etc.) while
delegating spatial computations and state mutations to the server.

Design decisions:
- ConnectRPC (connect-python) over plain REST because it gives us typed
  proto schemas, generated client/server stubs, and the Connect protocol
  works over standard HTTP/1.1 (no gRPC infrastructure needed).
- Proxies inherit from real resource types so backends that do
  isinstance(resource, Well) etc. work unchanged. A _SpatialMixin
  factors out the 7 overridden spatial methods.
- Immutable data (name, sizes, material properties, ordering) is held
  locally; mutable state (tracker volumes, tip presence, lid state,
  computed locations) always goes to the server to avoid staleness.
- connect-python stubs are hand-written (matching their codegen pattern)
  to avoid a build-time protoc-gen-connect-python dependency; the
  protobuf pb2/pyi files are generated via grpc_tools.protoc.

New optional dependency group: pip install PyLabRobot[remote]

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant