Send RPC and wait for response containing specific key with mandatory ID correlation (async). Useful when device may send multiple response types and you need to match a specific one. Args: function: RPC function name args: Function arguments
(
self,
function: str,
args: list[Any] | None = None,
match_key: str | None = None,
timeout: float | None = None,
retries: int = 3,
)
| 401 | ) |
| 402 | |
| 403 | async def send_and_match( |
| 404 | self, |
| 405 | function: str, |
| 406 | args: list[Any] | None = None, |
| 407 | match_key: str | None = None, |
| 408 | timeout: float | None = None, |
| 409 | retries: int = 3, |
| 410 | ) -> RpcResponse: |
| 411 | """Send RPC and wait for response containing specific key with mandatory ID correlation (async). |
| 412 | |
| 413 | Useful when device may send multiple response types and you need |
| 414 | to match a specific one. |
| 415 | |
| 416 | Args: |
| 417 | function: RPC function name |
| 418 | args: Function arguments |
| 419 | match_key: Key that must be present in response (e.g., "connected") |
| 420 | timeout: Override default timeout |
| 421 | retries: Number of retry attempts |
| 422 | |
| 423 | Returns: |
| 424 | RpcResponse containing the match_key and matching request ID (always includes ID) |
| 425 | |
| 426 | Raises: |
| 427 | RpcTimeoutError: If matching response not received |
| 428 | """ |
| 429 | if not self.is_connected: |
| 430 | raise RpcError("Not connected") |
| 431 | |
| 432 | assert self._serial is not None |
| 433 | |
| 434 | # Generate unique request ID for JSON-RPC 2.0 correlation (mandatory) |
| 435 | request_id = self._next_id |
| 436 | self._next_id = (self._next_id + 1) & 0xFFFFFFFF # Wrap at uint32 max |
| 437 | |
| 438 | # Wrap args in array to pass as single Json parameter to RPC functions |
| 439 | # RPC functions expect signature: (const fl::json& args) |
| 440 | # So we need to pass the entire args as one parameter |
| 441 | wrapped_args: list[Any] = [args] if args is not None else [{}] |
| 442 | cmd: dict[str, Any] = { |
| 443 | "method": function, |
| 444 | "params": wrapped_args, |
| 445 | "id": request_id, # ID is mandatory |
| 446 | } |
| 447 | cmd_str = json.dumps(cmd, separators=(",", ":")) |
| 448 | |
| 449 | if self.verbose: |
| 450 | print(f"📤 [RPC] Sending: {cmd_str}") |
| 451 | |
| 452 | effective_timeout = timeout if timeout is not None else self.timeout |
| 453 | attempt_timeout = effective_timeout / max(retries, 1) |
| 454 | |
| 455 | for _attempt in range(retries): |
| 456 | self._check_interrupt() # Check before each attempt |
| 457 | |
| 458 | # Write command via serial interface |
| 459 | await self._serial.write(cmd_str + "\n") |
| 460 |
no test coverage detected