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 a34ad90..0802302 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
@@ -1373,10 +1373,21 @@ class WebpageGeneratorBase:
by the HTML page as the 'Instrument details' section.
Expected keys (all optional):
- type (str) -- setup identifier, e.g. "flomni"
- sample_name (str) -- current sample name
- temperatures (dict) -- label -> float (degrees C) or None
- settings (dict) -- label -> formatted string
+ type (str) -- setup identifier, e.g. "flomni"
+ sample_name (str) -- current sample name
+ temperatures (dict) -- label -> float (degrees C) or None
+ current_params (dict) -- raw tomo parameters read live (keyed by
+ the same global-var names the tomo queue
+ stores in job.params, e.g. tomo_countingtime,
+ fovx, tomo_angle_stepsize, ...). Rendered by
+ the page through the same param-table path
+ as a queue job (buildParamRows), so the
+ 'Current measurement' section always matches
+ the queue's level of detail -- and shows the
+ details even for a scan started outside the
+ queue. Values are left raw; the page formats
+ them (fmtTqParam) and computes the projection
+ count (calcProjections).
"""
return {}
@@ -1402,10 +1413,31 @@ class WebpageGeneratorBase:
class FlomniWebpageGenerator(WebpageGeneratorBase):
"""
flOMNI-specific webpage generator.
- Adds: temperatures, sample name, measurement settings from global vars.
+ Adds: temperatures, sample name, and live current-measurement parameters
+ from global vars.
Logo: flOMNI.png from the same directory as this file.
"""
+ # Global-var names of the tomo parameters to read live for the
+ # 'Current measurement' section. Kept in the same order as, and matching,
+ # the tomo queue's TQ_PARAM_DISPLAY keys so the two render identically.
+ # (Any name that is not actually a global var is skipped silently and just
+ # does not appear as a row.)
+ _CURRENT_PARAM_KEYS = [
+ "tomo_type",
+ "tomo_countingtime",
+ "fovx",
+ "fovy",
+ "tomo_angle_stepsize",
+ "tomo_angle_range",
+ "tomo_shellstep",
+ "stitch_x",
+ "stitch_y",
+ "frames_per_trigger",
+ "single_point_instead_of_fermat_scan",
+ "ptycho_reconstruct_foldername",
+ ]
+
# label -> dotpath under device_manager.devices
_TEMP_MAP = {
"Heater": "flomni_temphum.temperature_heater",
@@ -1429,40 +1461,28 @@ class FlomniWebpageGenerator(WebpageGeneratorBase):
for label, path in self._TEMP_MAP.items()
}
- # ── Settings from global vars ─────────────────────────────────
+ # ── Current measurement parameters (read live) ────────────────
+ # Same keys the tomo queue stores in job.params, so the 'Current
+ # measurement' section on the page renders through the identical
+ # param-table path (buildParamRows -> fmtTqParam / calcProjections)
+ # and always matches the queue's level of detail. Reading these live
+ # means a tomo started OUTSIDE the queue still shows full parameters.
+ # Values are left raw; the page does the formatting.
g = self._bec
-
- def _fmt2(v):
+ current_params = {}
+ for key in self._CURRENT_PARAM_KEYS:
try:
- return f"{float(v):.2f}"
+ val = g.get_global_var(key)
except Exception:
- return "N/A"
-
- fovx = g.get_global_var("fovx")
- fovy = g.get_global_var("fovy")
- stx = g.get_global_var("stitch_x")
- sty = g.get_global_var("stitch_y")
-
- def _fmt_int(v):
- try:
- return str(int(v))
- except (TypeError, ValueError):
- return "N/A"
-
- settings = {
- "Sample name": sample_name,
- "FOV x / y": f"{_fmt2(fovx)} / {_fmt2(fovy)} \u00b5m",
- "Step size": _gvar(g, "tomo_shellstep", ".2f", " \u00b5m"),
- "Exposure time": _gvar(g, "tomo_countingtime", ".3f", " s"),
- "Angle step": _gvar(g, "tomo_angle_stepsize", ".2f", "\u00b0"),
- "Stitch x / y": f"{_fmt_int(stx)} / {_fmt_int(sty)}",
- }
+ val = None
+ if val is not None:
+ current_params[key] = val
return {
- "type": "flomni",
- "sample_name": sample_name,
- "temperatures": temperatures,
- "settings": settings,
+ "type": "flomni",
+ "sample_name": sample_name,
+ "temperatures": temperatures,
+ "current_params": current_params,
}
@@ -2656,12 +2676,18 @@ function esc(s){{return String(s==null?'N/A':s).replace(/&/g,'&').replace(/<
function renderInstrument(setup){{
const card=document.getElementById('instrument-card'),grid=document.getElementById('instrument-grid');
- if(!setup||(!setup.temperatures&&!setup.settings)){{card.style.display='none';return;}}
+ const cp=(setup&&setup.current_params)||null;
+ const hasParams=cp&&Object.keys(cp).length>0;
+ if(!setup||(!setup.temperatures&&!hasParams)){{card.style.display='none';return;}}
card.style.display='';
let html='';
- if(setup.settings){{
- html+='
Measurement settings
';
- for(const[k,v] of Object.entries(setup.settings)) html+='| '+esc(k)+' | '+esc(v)+' |
';
+ if(hasParams){{
+ // Same param-table path as a tomo queue job (buildParamRows), so the live
+ // 'Current measurement' matches the queue's level of detail — and shows
+ // full parameters even for a scan started outside the queue.
+ html+='Current measurement
';
+ if(setup.sample_name) html+='| Sample name | '+esc(setup.sample_name)+' |
';
+ html+=buildParamRows(cp);
html+='
';
}}
if(setup.temperatures){{
@@ -2761,6 +2787,24 @@ function calcProjections(params){{
return null;
}}
+// Build the tomo-parameter table rows for a params object, in TQ_PARAM_DISPLAY
+// order, injecting the computed Projections row after the angle step. Shared by
+// the tomo queue (per job) and the instrument 'Current measurement' section, so
+// both always show the same parameters, formatted the same way.
+function buildParamRows(params){{
+ let rows='';
+ TQ_PARAM_DISPLAY.forEach(([key,dispLabel])=>{{
+ if(key in params){{
+ rows+='| '+dispLabel+' | '+esc(fmtTqParam(key,params[key]))+' |
';
+ }}
+ if(key==='tomo_angle_stepsize'){{
+ const nproj=calcProjections(params);
+ if(nproj!=null) rows+='| Projections | '+nproj+' |
';
+ }}
+ }});
+ return rows;
+}}
+
function renderTomoQueue(jobs){{
const el=document.getElementById('tomo-queue-content');
if(!el) return; // setup has no tomo-queue card (HAS_TOMO_QUEUE=False)
@@ -2797,20 +2841,7 @@ function renderTomoQueue(jobs){{
shouldOpen=true;
autoOpened.add(key);
}}
- let paramRows='';
- TQ_PARAM_DISPLAY.forEach(([key,dispLabel])=>{{
- if(key in params){{
- paramRows+='| '+dispLabel+' | '+esc(fmtTqParam(key,params[key]))+' |
';
- }}
- // After angle step, inject a computed projection count row, driven by
- // this instrument's TOMO_TYPES config (must match the corresponding
- // Python-side formula, e.g. _tomo_type1_actual_grid() for flomni's
- // "equally_spaced_grid" type).
- if(key==='tomo_angle_stepsize'){{
- const nproj=calcProjections(params);
- if(nproj!=null) paramRows+='| Projections | '+nproj+' |
';
- }}
- }});
+ const paramRows=buildParamRows(params);
const addedAt=job.added_at
?'Added '+new Date(job.added_at).toLocaleString([],{{month:'short',day:'numeric',hour:'2-digit',minute:'2-digit'}})
:'';