From c50ac5c30cf329d8d6c39cf89e40fff8f4bd69f1 Mon Sep 17 00:00:00 2001 From: x12sa Date: Sun, 5 Jul 2026 08:53:30 +0200 Subject: [PATCH] webpage_generator: report blocked on interlock even when scan is interrupted A block interrupts the running scan, clearing active_request_block, so the old _derive_status() (which only returned 'blocked' inside the queue_has_active_scan branch) fell through to 'idle' with the blocked LED off, despite watched beamline states being out of spec. - _derive_status: return 'blocked' on beamline_blocking OR queue_locks, independent of active scan; only fresh-heartbeat 'scanning' outranks it. - _cycle: beamline_blocking = enabled is True AND any(state mismatched). Gated on enabled so a disabled/unknown interlock with an out-of-spec state does not raise BLOCKED. Also counted as activity so the idle clock restarts once cleared. - beamline-states card summary updated in lock-step: mismatched states are only called "currently blocking" when enabled, else "out of spec (interlock disabled/unknown, not blocking)", so pill and card can't disagree. - status-detail JS: describe blocking beamline states when no explicit queue lock is present. Update help text. --- .../flomni/flomni_webpage_generator.py | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/csaxs_bec/bec_ipython_client/plugins/flomni/flomni_webpage_generator.py b/csaxs_bec/bec_ipython_client/plugins/flomni/flomni_webpage_generator.py index 7613c76..8db13a1 100644 --- a/csaxs_bec/bec_ipython_client/plugins/flomni/flomni_webpage_generator.py +++ b/csaxs_bec/bec_ipython_client/plugins/flomni/flomni_webpage_generator.py @@ -1028,12 +1028,16 @@ class WebpageGeneratorBase: f"beamline_states read error: {exc}", level="warning") beamline_states_info = {"enabled": None, "states": []} - # True if any watched state is out of spec. Defined identically to the - # "N watched states currently blocking" count shown on the beamline - # states card (renderBeamlineStates: states.filter(s => s.mismatched)), + # True if the scan interlock is enabled AND at least one watched state + # is out of its accepted range. Gated on `enabled`: a mismatched state + # while the interlock is disabled does not actually block a scan, so it + # must not raise the 'blocked' status. Kept in lock-step with the + # beamline-states card summary (renderBeamlineStates), which likewise + # only calls mismatched states "blocking" when the interlock is enabled, # so the top status pill and that card can never disagree. - beamline_blocking = any( - s.get("mismatched") for s in beamline_states_info.get("states", []) + beamline_blocking = bool( + beamline_states_info.get("enabled") is True + and any(s.get("mismatched") for s in beamline_states_info.get("states", [])) ) # Current scan number (the BEC scan in progress right now, e.g. for @@ -2684,10 +2688,19 @@ function renderBeamlineStates(bl){{ return; }} - summary.innerHTML = 'Scan interlock '+enabledTxt+'' - + (mismatched.length>0 - ? ' · '+mismatched.length+' watched state'+(mismatched.length>1?'s':'')+' currently blocking' - : ' · all watched states OK'); + // "Blocking" only applies when the interlock is enabled — a mismatched + // state while disabled/unknown is out of spec but does not block a scan. + // Kept in lock-step with the Python beamline_blocking gate so this card and + // the top status pill never disagree. + let blockNote; + if(mismatched.length===0){{ + blockNote=' · all watched states OK'; + }} else if(bl&&bl.enabled===true){{ + blockNote=' · '+mismatched.length+' watched state'+(mismatched.length>1?'s':'')+' currently blocking'; + }} else {{ + blockNote=' · '+mismatched.length+' watched state'+(mismatched.length>1?'s':'')+' out of spec (interlock '+enabledTxt+', not blocking)'; + }} + summary.innerHTML = 'Scan interlock '+enabledTxt+''+blockNote; let html=''; states.forEach(s=>{{