Synchronize Operations with Wait Methods#
This guide shows how to use wait_for_value() and wait_for_predicate() to synchronize
operations in your FastCS driver.
Wait for a Specific Value#
Use wait_for_value() to pause execution until an attribute reaches an exact value:
from fastcs.attributes import AttrR
from fastcs.controllers import Controller
from fastcs.datatypes import Int
from fastcs.methods import command
class MotorController(Controller):
position: AttrR[int] = AttrR(Int())
target: AttrR[int] = AttrR(Int())
@command()
async def move_and_wait(self):
"""Move to target and wait until we arrive."""
target = self.target.get()
# Start the move (implementation depends on your device)
await self._start_move(target)
# Wait until position equals target (timeout after 30 seconds)
await self.position.wait_for_value(target, timeout=30.0)
Wait for a Condition with Predicates#
Use wait_for_predicate() for more complex conditions. The predicate is a callable that
takes the attribute value and returns True when the condition is satisfied:
from fastcs.attributes import AttrR
from fastcs.controllers import Controller
from fastcs.datatypes import Float
from fastcs.methods import command
class TemperatureController(Controller):
temperature: AttrR[float] = AttrR(Float())
@command()
async def wait_for_stable(self):
"""Wait until temperature is within operating range."""
def in_range(temp: float) -> bool:
return 20.0 <= temp <= 25.0
await self.temperature.wait_for_predicate(in_range, timeout=60.0)
Handling Timeouts#
Both methods raise TimeoutError if the condition isn’t met within the timeout period.
The error message includes the current value for debugging:
from fastcs.logging import logger
try:
await self.position.wait_for_value(100, timeout=5.0)
except TimeoutError:
logger.exception("Move timed out")
Early Return for Already Satisfied Conditions#
If the condition is already satisfied when called, both methods return immediately without creating an internal event:
# If position is already 100, this returns immediately
await self.position.wait_for_value(100, timeout=30.0)
# If temperature is already in range, this returns immediately
await self.temperature.wait_for_predicate(in_range, timeout=60.0)
Concurrent Waits#
Use asyncio.gather() to wait for multiple conditions simultaneously:
import asyncio
from fastcs.attributes import AttrR
from fastcs.controllers import Controller
from fastcs.datatypes import Float
from fastcs.methods import command
class MultiAxisController(Controller):
x_position = AttrR(Float())
y_position = AttrR(Float())
z_position = AttrR(Float())
@command()
async def move_all_and_wait(self):
"""Wait for all axes to reach their targets."""
await asyncio.gather(
self.x_position.wait_for_value(10.0, timeout=30.0),
self.y_position.wait_for_value(20.0, timeout=30.0),
self.z_position.wait_for_value(5.0, timeout=30.0),
)