17 Commits
Author SHA1 Message Date
Henrik Lemke e4d074cb86 features() and docs() in the session instead of URLs in the banner
features(): the "Did you know?" tip window (same as eco.tip()); docs():
the docs site in the web browser, or a given page (docs("scanning")),
printing the URL where there is no display. Both are imported into the
session at startup, and the banner names them instead of showing links.
2026-10-25 23:24:01 +01:00
Henrik Lemke 28aced6ded startup: docs and features links under the logo instead of a printed tip
The full tip at every session start was too much. The banner now shows two
links: the docs site and its random "Did you know?" page
(did_you_know/random.html); eco.tip() still shows tips in a window.
2026-10-25 23:16:50 +01:00
Henrik Lemke 4576ebcf18 eco.tip(): "Did you know?" tips at startup and in a small Qt window
- eco/utilities/tips.py reads docs/did_you_know/*.md (front matter, title,
  body), prints a tip in the terminal and keeps the session's tip history:
  Back/Next walk the tips already seen, and only past the end is a new
  random one picked (unseen first).
- eco/widgets/tip_qt.py: the window behind eco.tip() (Back / Next / Open in
  docs, arrow keys, one window per session). Without a display, eco.tip()
  prints the next tip instead.
- eco/startup_inline.py prints one tip at session start, pointing at
  eco.tip(); ECO_NO_TIP=1 turns it off.
- Links in tips point at the docs site (ECO_DOCS_URL, default
  saresb-cons-04:8095).
2026-10-25 23:08:13 +01:00
lemke_h cf8f5de66f archiver: bin long ranges on the server automatically (max_bins)
A channel with more than max_bins (default 100000) events in the requested
range comes binned on the server (round bin width, average plus min/max/count
columns) instead of raw, the way databoard does it: 24 h of one 100 Hz BS
channel was 23 s and 3 GB raw, now about 5 s. Channels with fewer events stay
raw. A warning names the binned channels; bins= chooses the binning
explicitly, max_bins=None always fetches raw events.
2026-10-25 15:16:05 +01:00
Henrik Lemke 83facbfcce docs: did_you_know/random.html - one random tip, no sidebar, for a small window
Written after each html build (conf.py build-finished hook) from
_templates/random_tip.html with the current list of tips; ?tip=<name> shows
a given one. Meant for e.g.
  google-chrome --app=http://<host>:8095/did_you_know/random.html --window-size=560,460
Also shorten the picker tip's code lines to fit such a window.
2026-10-25 14:51:56 +01:00
Henrik Lemke 98d8e4a0c5 docs: "Did you know?" tips, pages for recent features, and a docs-site job
- docs/did_you_know/: one short tip per feature added since May 2026
  (<date>-<slug>.md, YAML front matter: added/tags/details), listed
  newest first; index.md describes the format for adding more.
- New pages for features that had none: launching, command_history,
  tab_completion, live_gui, tweak, scanning, status_server,
  channel_access, shared_files, schematic_panels. Wired into index.rst
  together with the existing queues page.
- Fix archiver_stripchart/listening_monitor: the method is
  archiver.strip_plot (strip_chart does not exist on DataHub); document
  the per-device .strip_plot().
- NAMESPACE_MONITOR_FORMAT.md: scan monitoring is wired into Daq's scan
  callbacks since 2026-09-09.
- scripts/eco-docs (+ -install-user-service): build the docs from an own
  clone and serve them over HTTP as user systemd units, rebuilt by a
  timer; a failed build never replaces the served site.
2026-10-25 14:26:52 +01:00
Henrik Lemke 5b6f2d2838 Property grids: live, non-blocking on Qt, ipywidgets/Voila and Tk
- shared eco.widgets.live_values: writes on a background thread with a
  status dot (and working Stop during a move), reads off the GUI/kernel
  thread, monitored items subscribed (trusted only once an event arrives,
  demoted if a poll sees an unannounced change), tweak step from the IOC's
  TWV for motor/SmarAct records.
- assembly_browser Set no longer falls back to mvr (a relative move with
  an absolute value); runs off the kernel thread.
- fix process aborts: IOC finder worker destroyed while running, simple
  gadget polling after close; tweak panel message timer guarded.
2026-10-25 14:25:03 +01:00
Henrik Lemke 8ed1a4315f Main-thread heartbeat, named task queues, thread-aware input
- eco.utilities.mainthread: a watchdog interrupts the main thread (SIGUSR2)
  while a cell blocks, so Qt windows (camera viewers, plots, the desktop
  workbench) stay live during umv/scans/sleep; call_soon/on_main for GUI
  work from other threads. Camera viewers default to in-process again.
- eco.utilities.task_queue: named queues (queues[name], %queue magic,
  scans.*(queue=...)) replacing scan_queue.py; every append is test-run
  (names, signatures, scan build, limits); claims block moves of a running
  task's adjustables from elsewhere (forced() overrides); output capture,
  recording and an output window (queue_output_qt).
- eco.utilities.user_input: input() from a worker asks on the main thread;
  input_timeout(escalate=False) takes the default at once inside a queue.
- scan: start_time %M -> %m bug fixed; GUI calls in scan callbacks routed
  to the main thread.
2026-10-25 14:25:03 +01:00
Henrik Lemke ab8b704c8b tweak: live text plot in the terminal when there is no display
With ECO_NO_X=1 or without X, the terminal tweak's detector recording
now plots as text (uniplot) just above the status line, redrawn in place
as points come in -- same layout as the Qt plot: detector(s) vs position
for one adjustable, detectors over positions vs step for several.

New eco.utilities.termplot, the wrapper planned in docs/terminal_plots.md:
panel_stack() for stacked plots over a shared x, and LiveRegion /
LivePlotter for in-place redraws that coexist with a '\r' status line
(prints a fresh copy if other output scrolled in between).
2026-10-08 11:29:55 +02:00
Henrik Lemke aa98259f3e docs: terminal plots via uniplot, and its shortcomings
Records the decision to use uniplot (in sfb312) for no-display terminal
plots behind an eco wrapper, the gaps that could justify an own copy
later, and the alternatives considered.
2026-10-08 08:38:57 +02:00
lemke_h 48dbc9c6fd fixes 2026-10-05 22:29:03 +02:00
lemke_h 6710fa1c85 more fixes 2026-08-28 18:20:00 +02:00
lemke_h e3d801a38c fix prepump 2026-08-28 15:06:45 +02:00
lemke_h 9c87c23d18 fixes 2026-08-28 14:25:39 +02:00
gac berninaandClaude Sonnet 5 cadfcd2667 Restructure eco CLI into subcommands; fix namespace resolution and add required-checkbox launchers
CLI: eco --ui {shell,lab,voila,desktop} -> subcommands eco {console,desktop,
webapp,jupyterlab}, console being the default (bare `eco` == `eco console`).
desktop's -s/--scope has no forced default any more: without it you get a
plain embedded Qt console with no Namespace launcher panel, instead of
silently defaulting to bernina. Both desktop and jupyterlab get a
--console/--no-console flag (console on by default). jupyterlab, when given
-s, now registers a real eco-<scope> Jupyter kernel (IPython profile startup
file + kernelspec, regenerated each launch) and makes it JupyterLab's
default kernel, then opens a real `jupyter console` on it in the launching
terminal -- so a fresh Console/Notebook opened from JupyterLab's own
launcher gets eco.<scope> preloaded too, not just one pre-built notebook.
Also added --set-rcfile [PATH] to persist the current invocation into an
.ecorc instead of launching.

Real bug found and fixed: Namespace.append_obj writes constructed/lazy
device objects onto sys.modules[root_module] (the scope module, e.g.
eco.bernina), not onto the Namespace instance itself -- the instance only
tracks name -> state bookkeeping (lazy_items/failed_items/initialized_items).
eco.widgets.desktop_app's launcher panel and console-namespace-population
both assumed `getattr(namespace, name)` worked, which silently raised
AttributeError for every single namespace entry -- opening or initializing
anything from the desktop launcher failed outright. Added
Namespace.resolve_item() as the canonical fix (the lazy-or-failed-or-
initialized dict chain reinitialize() itself already used internally) and
build_namespace_vars() (mirrors `from eco.<scope> import *` -- bare names
like mono/att, not just a `namespace` variable) for both the in-process and
subprocess console-kernel paths.

Also ported this same fix to eco.widgets.widget_tray (the ipywidgets
dashboard backing webapp/jupyterlab), replacing the old status_collection-
based member dropdown (initialized-only, no lazy/failed visibility) with a
NamespaceLauncherWidget matching desktop's launcher: browse every
registered name including lazy/failed ones, click to initialize+open.

New: a Required column/checkbox (Namespace.required_names()) in both
launchers -- desktop's Qt _NamespaceLauncher (QListWidget -> QTableWidget,
Name + Required columns) and the new ipywidgets NamespaceLauncherWidget.

Verified via eco-dev across all four subcommands against the real bernina
scope (shell/console, desktop with and without -s, webapp, jupyterlab
including the registered-kernel mechanism via a live jupyter_client
KernelManager), plus the full test suite (44/44 in test_desktop_app.py,
323/325 overall -- the 2 failures are pre-existing in
test_config_lazy_init.py, unrelated to any of this).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 20:01:05 +02:00
gac berninaandClaude Sonnet 5 779a93cfa6 Rename eco.epics -> eco.epics_utils to stop shadowing pyepics; rework eco --help
eco shipped its own subpackage literally named eco/epics/, colliding with
the third-party `epics` (pyepics) package. Whenever eco's own package
directory landed on sys.path, `import epics.pv` resolved to eco's shadow
instead of pyepics. The previous commit patched one trigger (eco_cli.py's
shell UI), but --ui lab/voila hit the identical collision via a different
route: voila_app.ipynb lives inside eco/, and Jupyter/Voila kernels start
with the notebook's own directory as sys.path[0]. Confirmed via eco-dev:
both lab and voila's dashboard execution failed with the exact same
ModuleNotFoundError: No module named 'epics.pv'.

Renaming the subpackage (eco.epics -> eco.epics_utils, ~90 mechanical
import-line updates) removes the collision at the root, regardless of
trigger. Verified via eco-dev across all four --ui modes (shell, lab,
voila, desktop) with no more epics.pv errors anywhere.

Also reworked eco_cli.py's --help: shows [default] on -l/--lazy, adds a
full description of all four --ui front-ends including desktop, documents
.ecorc configuration, and adds --set-rcfile [PATH] to persist the current
invocation's scope/profile/lazy/ui into an .ecorc instead of launching.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 16:17:33 +02:00
gac bernina a01556e584 big blast of changes. 2026-08-18 21:56:17 +02:00