tell_client: restore "No Pin in Gripper" detection on empty-gripper mount

Commit 071b4ab made mount() return SUCCESS as soon as it saw the intermediate
TELL "state"/Busy event, before the later "Gripper detection" event is read,
so an empty-gripper mount completed silently with no MountingFailed/pop-up.

check_command_ok blocks (wait_not_busy) until the mount sequence finishes, so
after it returns the robot's own record is authoritative: if get_mounted_sample()
is None the gripper was empty -> return NO_PIN_IN_GRIPPER, which the mounting
service maps to MountingFailed("No Pin in Gripper"). Covers manual and automation.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
appleb_m
2026-06-24 15:30:08 +02:00
co-authored by Claude Opus 4.8
parent 47e05dc28c
commit 5370c0f168
3 changed files with 33 additions and 0 deletions
+1
View File
@@ -30,6 +30,7 @@
- `/status` now publishes `pss_prohibited`/`pss_alarm`; the GUI blocks manual mount/unmount and the automation Run button immediately (with a pop-up) when the hutch door is open, instead of letting the robot fail to move server-side.
- Centralised the per-action precondition checks (ring current, safety shutter, hutch door) into one combined "continue?" dialog used by all data-collection buttons (Evaluate grid, X-ray centering, Run screening/rotation/fluorescence, simple rotation), with a session-global "Don't ask me again for 1 hour" snooze.
- Live automation now pauses and auto-resumes when the beam, experiment shutter, hutch door or robot (TELL) are not ready (with Continue-now / Stop overrides), gated by a "Pause on bad conditions" checkbox (default on) that replaces the dead `CHECK_ENABLED` constant.
- Restored "No Pin in Gripper" detection: a mount that returns on the intermediate TELL "Busy" state event now verifies the robot's `get_mounted_sample()` after the command completes, so an empty-gripper mount surfaces `MountingFailed` (and the GUI pop-up) instead of silently reporting success.
## 0.3.1 (2026-04-29)
- **DAQ/Server**:
+9
View File
@@ -293,6 +293,15 @@ class TellClient:
timeout=wait_timeout, msg=f"Mount {segment}{puck}-{sample}: "
)
logger.info(f"Check command okay response: {msg}")
# check_command_ok blocks (wait_not_busy) until the whole
# mount sequence has finished, so the gripper-detection event
# we observed as an intermediate "state"/Busy event is now
# resolved. The robot's own record is authoritative: if it
# reports nothing mounted, the gripper was empty (no pin),
# which we must surface rather than reporting success.
if self.get_mounted_sample() is None:
logger.warning("Mount command completed but robot reports no sample mounted")
return TellEventValueEnum.NO_PIN_IN_GRIPPER
return TellEventValueEnum.SUCCESS
elif (
event == TellEventTypeEnum.GIPPER_DETECTION.value
+23
View File
@@ -52,6 +52,8 @@ def test_mount_state_event_succeeds_when_command_completes(
"id": 3017907,
}
client = TellClient(mock_beamline, backend=mock_backend)
# Robot reports the requested sample as mounted -> genuine success.
client.get_mounted_sample = lambda: _mount_address()
result = client.mount(_mount_address(), wait=True)
@@ -59,6 +61,27 @@ def test_mount_state_event_succeeds_when_command_completes(
mock_backend.get_result.assert_called() # check_command_ok consulted the result
def test_mount_state_event_reports_no_pin_when_nothing_mounted(
mock_beamline, mock_backend
):
"""If the command completes but the robot reports nothing mounted, the
gripper was empty: mount() must return NO_PIN_IN_GRIPPER (so the service
raises MountingFailed) rather than reporting success."""
mock_backend.wait_events.return_value = ("state", "Busy")
mock_backend.get_result.return_value = {
"status": "completed",
"return": "A39",
"exception": None,
"id": 3017907,
}
client = TellClient(mock_beamline, backend=mock_backend)
client.get_mounted_sample = lambda: None
result = client.mount(_mount_address(), wait=True)
assert result == TellEventValueEnum.NO_PIN_IN_GRIPPER
def test_mount_state_event_raises_when_command_not_completed(
mock_beamline, mock_backend
):