Files
uopi/docs/FUNCTIONAL_SPEC.md
T
Martino Ferrari f7f297c3df Add synthetic array (waveform) DSP support + UX improvements
Adds full array/waveform support through the synthetic DSP engine: a
dsp.Sample value model (scalar or []float64), array ops (index, slice,
sum, mean, min, max, length, fft) with an in-tree radix-2 FFT, and static
type propagation (OpOutputType) that the editor mirrors to colour wires by
data type and flag invalid wirings. Stateful filters and lua stay
scalar-only. Adds a waveform plot mode (x-vs-index trace).

Also: errored-node hover reasons, S/N add-signal/add-node HUD shortcuts in
the synthetic editor, and view-mode widgets that blend with the canvas
background (chrome kept in edit mode).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-20 17:06:55 +02:00

16 KiB
Raw Blame History

Functional Specification — uopi

1. Purpose

uopi is a web-based HMI (Human-Machine Interface) for monitoring and controlling industrial/scientific systems, primarily EPICS-based control systems. It runs as a single server process and is accessed entirely through a web browser, making it suitable for SSH-tunnelled remote access.


2. Users and Roles

User identity is established from a header set by a trusted authenticating reverse proxy (server.trusted_user_header), with a configurable default_user fallback for unproxied/LAN deployments. There is no login page inside the application.

Global access levels. Every user is trusted with full write access by default. A configuration blacklist can downgrade specific users to read-only (view only, no writes) or no access (denied). Named groups are defined in configuration and referenced by per-panel sharing.

Per-panel access. Panels are owned by their creator and private by default. Owners share a panel with specific users/groups (read or write) or make it public; the owner's global level always caps the per-panel permission. Panels are organised into nested folders whose permissions inherit down the chain. See §9.

Logic-edit restriction. Adding/editing panel logic and server-side control logic can optionally be limited to an allowlist of users/groups (server.logic_editors); when unset, any writer may edit logic.


3. System Modes

3.1 View Mode (default)

The default mode when opening the application.

Interface list pane (left, collapsible, resizable)

  • Displays all interfaces saved on the server.
  • Right-click on an interface: options to open in Edit mode or clone it.
  • "New interface" button opens Edit mode with a blank canvas.
  • The pane width can be adjusted by dragging the resize handle on its right edge.

HMI canvas (center)

  • Renders the selected interface as a live, interactive panel.
  • Widgets display real-time data; controls (set-value, buttons) are active.
  • Panel logic (if any) runs while the panel is open (see §6).
  • No drag, resize, or layout operations are possible in this mode.
  • Right-clicking any widget opens a context menu:
    • Signal info — shows DS name, type, unit, range, current value and timestamp.
    • Copy signal name — copies the signal identifier to the clipboard.
    • Export data to CSV — downloads buffered data for the signal(s) used by the widget.

Dedicated multi-signal plotting is provided by plot panels — a special interface kind whose plots fill the viewport (see §3.3) — rather than a separate live "Plot tab".

Top toolbar

  • Show/hide interface list pane.
  • ⏱ History button: toggle historical time navigation bar.
  • ⚙ Control logic button: open the server-side control-logic editor (see §7). Shown only to users permitted to edit logic.
  • Zoom control (A / % / A+): adjust the UI scale (see §3.4).
  • Edit button: switch to Edit mode for the current interface.
  • Connection status indicator and signed-in user chip.

Historical time navigation bar (shown when History is active)

  • Date/time range pickers (start and end).
  • Load button fetches archive data and replaces live data in all widgets.
  • Live button discards archive data and resumes real-time streaming.
  • Status shown on plot widgets: "Loading history…", "No archive data for this range", "Archive unavailable".

3.2 Edit Mode

Activated via the "New interface" button or by clicking Edit in the toolbar.

Signal tree pane (left, resizable and collapsible)

  • Shows all signals known to each connected data source.
  • Sources are shown as top-level nodes; signals are nested within.
  • User can add custom entries:
    • For EPICS: manually enter a PV name.
    • For Synthetic: define a new synthetic signal via the Synthetic Wizard (see §5.2).
  • Filter/search box to narrow the list.
  • Synthetic signals show an edit (✎) button to reopen the wizard.

Center area — Layout / Logic tabs

  • Layout: free-form canvas where widgets can be placed at arbitrary pixel positions, over a background grid with snap-to-grid. (For plot panels this is replaced by the split-layout editor; see §3.3.)
  • Logic: a node-graph flow editor for panel behaviour (see §6). Hidden when the user is not permitted to edit logic.

Local variables

  • A panel may declare panel-scoped variables (data source local) with initial values.
  • They are written by set-value widgets, buttons and logic actions, and referenced anywhere a signal is. Added from the signal tree's Local group / the Logic palette.

Properties pane (right, resizable and collapsible)

  • Appears when one or more widgets are selected.
  • Displays and edits all options for the selected widget (see §4).
  • Width is adjustable by dragging the resize handle on its left edge.

Top toolbar

  • Show/hide signal pane / properties pane.
  • Undo / Redo (also Ctrl+Z / Ctrl+Shift+Z).
  • Import / Export interface to/from local XML file.
  • Save interface to server.
  • Close (return to View mode).
  • Zoom control (A / % / A+).

3.3 Plot Panels (Split Layout)

A plot panel is a special interface kind dedicated to charts. Rather than free-form widget boxes, plots fill the viewport and the user divides the space between them with a recursive split layout (tmux/IDE-style tiling). Created via + Plot in the interface list, opening with a single full-viewport empty plot.

Editing (Edit mode):

  • Hover a pane and use its split buttons ( vertical / horizontal) to divide it; a new empty plot fills the freed half. Nesting is unlimited.
  • Drag the divider between two panes to resize them.
  • Click a pane to select it and configure its plot in the Properties pane (plot sub-type, Y range, time window, legend, per-signal colour). Drag a signal onto a pane to add it.
  • A pane's removes it; the layout collapses onto its sibling.

View mode: the saved split layout fills the screen with live, streaming plots; the per-widget right-click menu (signal info / copy / CSV) and historical time navigation apply as for any time-series plot.

Per-plot configuration reuses the standard Plot widget (§4.4), so all plot sub-types and options are available within a pane.

3.4 UI Zoom

The toolbar in both modes contains a zoom control (A / nn% / A+) that adjusts the base font size of the entire UI:

  • 11 zoom steps from 50% to 250% (50, 60, 75, 85, 100, 115, 130, 150, 175, 200, 250%).
  • The selected zoom level is persisted in localStorage and restored on the next page load.
  • At 100%, the base font size adapts to viewport height via clamp(13px, 1.5vh, 18px), making the UI naturally usable on 4K displays without any manual adjustment.

4. Widgets

4.1 Creating Widgets

Drag a signal from the signal tree and drop it onto the canvas. A picker appears showing all widget types compatible with the signal's data type. The user selects one and the widget is placed at the drop location with default size.

4.2 Selecting Widgets

  • Single click: select one widget (deselects others).
  • Ctrl+click: add/remove a widget from the current selection.
  • Click-drag on empty canvas area: rubber-band area select.

When a widget is selected, a bounding box appears with:

  • 8 resize handles (corners + midpoints).
  • A delete button (×) in the top-right corner.
  • The widget can be moved by dragging its body.

4.3 Multi-selection Operations

When multiple widgets are selected:

  • Drag any selected widget to move them all together.
  • Del key deletes all selected widgets.
  • An align/distribute toolbar appears above the canvas with:
    • Align left / center horizontal / right.
    • Align top / center vertical / bottom.
    • Distribute evenly (horizontal/vertical).

4.4 Widget Catalogue

Widget Compatible signal types Description
Text view any scalar Displays name: value unit
Gauge numeric scalar Circular or arc gauge with configurable range
Vertical bar numeric scalar Vertical level indicator
Horizontal bar numeric scalar Horizontal level indicator
Set value numeric, string, or enum; writable Input field or enum dropdown + Set button
LED boolean / numeric Coloured indicator with configurable condition and label
Multi-LED integer (bitset) One LED per bit with individual labels and conditions
Button writable Sends a fixed value or command on click
Plot numeric scalar or array Multi-signal plot; sub-types below
Text label Static text annotation
Image Static image
Link Button navigating to another interface

Plot sub-types:

Sub-type Signal requirement
Time series numeric scalar(s)
FFT 1-D numeric array
Waterfall 1-D numeric array (repeated)
Histogram numeric scalar(s)
Bar chart numeric scalar(s)
Logic analyser boolean / integer (bitset)
Waveform 1-D numeric array (latest sample, x-vs-index)

4.5 Widget Properties (Properties Pane)

Common to all:

  • Label text, font size, text colour.
  • Position (X, Y) and size (W, H) — editable numerically.
  • Data source and signal name.

Per type:

  • Gauge / Bar: min value, max value, alert thresholds with colours, unit label.
  • LED / Multi-LED: condition expression (e.g. value > 0), colours for true/false states, label.
  • Plot: plot sub-type selector, Y-axis range (auto or manual min/max), time window duration, legend position (top / bottom / none), value format string.
  • Set value: no special options — enum mode is detected automatically from signal metadata.
  • Link: target interface name.

4.6 Set-value Widget — Enum Mode

When the signal's metadata reports enum strings (e.g. EPICS mbbi/mbbo records):

  • The input field is replaced by a <select> dropdown showing all enum options.
  • The current live value is shown as the pre-selected option (display only).
  • The user selects a value from the dropdown, then clicks Set to write it.
  • The Set button is always required; changing the dropdown does not write immediately.

5. Data Sources

5.1 EPICS

  • Connects to an EPICS environment via Channel Access (CA).
  • On connect, retrieves full metadata from the PV name: data type, engineering units, display range, alarm limits, enum strings (for mbbi/mbbo records), read/write mode.
  • Uses ca_add_event monitors — no polling.
  • When an EPICS Archive Appliance is configured, the server can satisfy historical data requests from the toolbar time navigator.

5.2 Synthetic Signals

A signal defined by composing one or more input signals through a chain of processing nodes.

Two authoring surfaces:

  • Wizard — for the common single-input case: name the signal, pick an input and a processing node, set parameters, Create.
  • Node-graph editor — a visual editor that wires one or more inputs through a chain of DSP blocks, for multi-input pipelines. It compiles to the same inputs + pipeline model.

Visibility scope: each synthetic signal is scoped as panel (visible only to the panel that created it), user, or global (shared with everyone).

The dialogs are resizable and default to a width that accommodates the Lua editor.

Editing an existing synthetic signal: click the ✎ button next to the signal in the tree to reopen the editor.

Built-in node types:

Node Parameters Description
Source DS, signal name Input from any data source
Gain factor Multiply by constant
Offset value Add constant
Moving average window (samples) Rolling mean
Low-pass filter frequency (Hz), order (18) IIR low-pass; correct for non-uniform sample rates
Formula expression Inline math (variables: a, b, …)
Lua script script Arbitrary Lua 5.1 with persistent state table

Lua editor: the Lua node parameter uses a code editor with syntax highlighting (keywords, strings, comments, numbers rendered in distinct colours). The editor is a full-height multi-line input that grows with the dialog.


6. Panel Logic

The Logic tab in the panel editor is a node-graph (Node-RED-style) flow editor that gives a panel interactive behaviour. The flow runs client-side while the panel is open in View mode; it is saved as part of the interface XML. The tab and any logic editing are gated by the logic-edit restriction (§2).

Authoring: drag blocks from the palette (or click to add), connect output ports to input ports, and edit the selected node in the inspector. Expression fields reference a signal as {ds:name} and a panel-local variable by its bare name, and support arithmetic, comparisons, boolean logic and common math functions. The editor has its own undo/redo and copy/paste.

Node categories:

Category Nodes
Triggers Button press, threshold crossing, value change, timer/interval, panel loop, On-open / On-close lifecycle
Logic AND gate, If (then/else), Loop (count or while)
Actions Write to signal/variable, Delay, Log; Accumulate / Export-CSV / Clear for in-memory data arrays
Dialogs Info and Error pop-ups; Set-point prompt (asks the user for a number and writes it)

System helpers in expressions: {sys:time} (epoch seconds) and {sys:dt} (seconds since the firing trigger last fired).


7. Control Logic

Control logic is server-side automation: flow graphs that run continuously on the server, independent of any connected client (unlike panel logic, which only runs while a panel is open). Opened with the ⚙ Control logic button in the View-mode toolbar and managed through the REST API.

  • Triggers include cron schedules and signal alarm/threshold conditions.
  • A Lua block provides custom logic; results are written back to signals.
  • Each graph can be enabled/disabled independently; saving reloads the engine live.
  • Editing is gated by the logic-edit restriction (§2).

8. Interface Persistence

  • Interfaces are saved to the server in XML format and are available to all connected clients.
  • Per-panel access rules and panel-folder placement are stored server-side (sidecar JSON).
  • Saved versions are retained; a panel's version history can be listed, tagged and promoted.
  • Export/Import allows local file exchange of XML files.
  • The XML schema records: interface kind (panel/plot) and split layout, widget type, position, size, signal bindings, all property values, local variables, and panel logic.

9. Access Control, Sharing & Folders

Identity is resolved per request from the trusted proxy header, falling back to default_user. The /api/v1/me endpoint reports the caller's identity, global level, group memberships and whether they may edit logic; the UI hides affordances accordingly.

Global levels (§2): write (default), read-only, or no-access via the config blacklist.

Per-panel sharing: the Share dialog on a panel grants read or write to specific users or groups, or marks the panel public. New panels are private to their owner. The owner's global level caps any per-panel grant.

Folders: panels are organised into nested folders; permissions inherit down the folder chain. Panels can be dragged to reorder or move between folders.

Logic-editor allowlist: when server.logic_editors is set, only the listed users/ groups may add or change panel logic and control logic; everyone else keeps full access to the rest of the application.


10. Historical Data Navigation

When the server has archive access configured:

  • The ⏱ History button in the View mode toolbar reveals a time range bar.
  • Users set a start and end date/time and click Load.
  • Plot widgets fetch and display the archived data for the selected range.
  • Point-value widgets (text view, gauge, bar, LED) show the value at the end of the selected range.
  • The Live button resumes real-time streaming.
  • Status overlays on plot widgets indicate loading, empty, or error states.

11. Non-functional Requirements

Requirement Target
Server binary Single statically-linked executable; no runtime dependencies
Target platform Linux x86-64; also aarch64 optional
Minimum server OS RHEL/CentOS 7 (glibc 2.17) or equivalent
Concurrent clients ≥ 20 simultaneous browser clients
Data fan-out latency < 5 ms added latency vs. raw EPICS update rate
Frontend responsiveness 60 fps canvas rendering during live updates
Screen DPI UI scales with viewport height; manual zoom 50250%
Plot buffer 200,000 samples per signal retained in-browser