Repeated Modules
Pick the pattern by asking whether the instances work independently:
| The instances are… | Use | Example |
|---|---|---|
| Independent modules that each do their own work | One parametrized feature, registered per instance | Pump channels, pipette channels, bioreactor chambers |
| Interchangeable positions on one resource | One feature with a slot parameter | Slots in a centrifuge or plate hotel |
For the reasoning behind this choice, see Designing Features.
Register one feature per independent module
Write one class and pass the instance index to its constructor. Inject the index into the feature name through name=, placing it before the role suffix:
class PipetteService(sila.Feature):
"""Aspirate and dispense with a single pipetting channel."""
def __init__(self, protocol: "LiquidHandlerProtocol", channel: int):
super().__init__(
originator="io.unitelabs",
category="liquidhandling",
name=f"Pipette {channel} Service",
)
self.protocol = protocol
self.channel = channel
for channel in range(1, 9):
app.register(PipetteService(protocol, channel=channel))
Clients see Pipette1Service through Pipette8Service, each addressing one channel. Don't hardcode the index into separate classes, and don't put it after the suffix: Door1Controller, not DoorController1.
Use a slot parameter for interchangeable positions
When the positions belong to one logical resource, expose one feature and take the slot as a parameter, constrained to the valid range:
class AccessCompartmentController(sila.Feature):
"""Open and close the access compartments of the centrifuge rotor."""
@sila.ObservableCommand()
async def open(
self,
slot: typing.Annotated[int, sila.constraints.MinimalInclusive(1), sila.constraints.MaximalInclusive(4)],
*,
status: sila.Status,
) -> None:
"""
Open the access compartment at the given slot.
Args:
Slot: The slot to open.
"""
This replaces Door1Controller.open(), Door2Controller.open(), and so on, which would split one concern across features that depend on each other. If the number of slots depends on the device, add the maximum at startup instead. See Constraints and Units.
Last updated