Sample-storage events#
HighRes sample stores emit structured events for plate transfers and changes to environmental control. Event observation is optional and does not change device behavior.
Every operation listed below emits one of these correlated lifecycle sequences when an active EventBus has a subscriber:
<operation>.started -> <operation>.completed
<operation>.started -> <operation>.failed
The two records share context.operation_id. A failed record also contains error_type and
error_message.
Quickstart#
Subscribe after setting up the store, then wrap the operations that should be observed:
from pylabrobot.events import EventBus, use_event_bus
event_bus = EventBus()
event_bus.subscribe(lambda event: print(event.as_dict()))
await store.setup()
with use_event_bus(event_bus):
await store.fetch_plate_to_loading_tray("plate_1", tray_index=0)
await store.environment.set_temperature(37)
Use set_default_event_bus() instead when one process-wide bus should observe every instrumented
operation. See the general EventBus guide for event
shape, application context, and subscriber behavior.
Transfer events#
Operation |
Emitted by |
Fields |
|---|---|---|
|
|
|
|
|
|
|
|
|
resources contains the plate being moved. source and destination identify the actual
PlateHolder resources: a stacker slot and a device-reported transfer nest.
The transfer event encloses both the hardware command and PLR bookkeeping. A successful transfer
therefore produces this sequence, all with the same operation_id:
incubator.fetch_plate.started
resource.unassigned
resource.assigned
incubator.fetch_plate.completed
For take_in_plate() and store_plate(), the equivalent outer event is
incubator.take_in_plate; nest-to-nest moves use incubator.transfer_plate. If validation or
hardware motion fails after the operation begins, the plate remains at its original PLR location
and the outer operation emits .failed.
Example invocation data:
{
"device": {"name": "steristore", "type": "SteriStore", "model": "SteriStore"},
"resources": [{"name": "plate_1", "type": "Plate"}],
"source": {"name": "rack_1_slot_3", "type": "PlateHolder"},
"destination": {"name": "steristore_nest_1", "type": "PlateHolder"},
}
Resource references may also contain rotation and ancestor information.
Environmental-control events#
Environmental events identify the sample store in device and use an empty resources list.
Humidity and gas targets are fractions, matching the Python API: 0.90 means 90% RH and 0.05
means 5% gas concentration.
Control |
Models |
|---|---|
Temperature |
SteriStore and TundraStore |
Relative humidity |
SteriStore and TundraStore |
CO2 |
SteriStore |
O2 |
SteriStore when the optional controllable channel is installed |
AmbiStore does not expose store.environment, so it emits only transfer events.
Operation |
Emitted by |
Additional invocation fields |
|---|---|---|
|
|
|
|
|
— |
|
|
— |
|
|
|
|
|
— |
|
|
— |
|
|
|
|
|
— |
|
|
— |
|
|
|
|
|
— |
|
|
— |
For example, await store.environment.set_co2(0.05) emits
co2_controller.set_co2.started followed by either co2_controller.set_co2.completed or
co2_controller.set_co2.failed:
{
"device": {"name": "steristore", "type": "SteriStore", "model": "SteriStore"},
"resources": [],
"target_co2": 0.05,
}
Calling an unavailable channel is observable as a failed operation. For example, attempting O2
control on a store without an installed controllable O2 channel emits
o2_controller.set_o2.failed with error_type="NotImplementedError".
Operations without semantic events#
Read-only status methods do not emit semantic operation events. This includes environmental
reads, tank-pressure reads, version and status requests, and inventory queries. setup(),
stop(), homing, recovery, door control, and clear-abort are also not currently
instrumented as semantic operations.
Generic resource.assigned and resource.unassigned state events can still be emitted whenever
PLR resource bookkeeping changes, including nest creation during initial setup when an EventBus is
active.