2026-06-23 17:59:40 +02:00
2026-06-23 17:59:40 +02:00
2026-06-23 17:59:40 +02:00
2026-05-04 21:13:36 +02:00
2026-06-23 17:59:40 +02:00
2026-04-30 23:01:01 +02:00
2026-04-25 22:56:09 +02:00
2026-06-23 17:59:40 +02:00
2026-06-23 17:59:40 +02:00
2026-04-30 23:01:01 +02:00
2026-06-23 17:59:40 +02:00
2026-06-21 23:50:03 +02:00
2026-04-24 15:09:14 +02:00
2026-04-25 22:56:09 +02:00
2026-06-23 17:59:40 +02:00

uopi

A web-based HMI (Human-Machine Interface) for monitoring and controlling EPICS-based scientific and industrial control systems.

uopi runs as a single portable binary with no runtime dependencies. Point any browser at it — including over an SSH tunnel — and you get a full drag-and-drop HMI builder and live data viewer.


Features

Feature Details
Live data EPICS Channel Access (CA) / PVAccess and user-defined synthetic signals
HMI editor Drag-and-drop widgets, resize, align/distribute, undo/redo, saved as XML
Widget library Text view/label, gauge, LED, multi-LED, bar, set-point control, button, image, link, plots
Plot types Time-series (uPlot), FFT, waterfall, histogram, bar chart, logic analyser
Plot panels Dedicated chart panels with a recursive split layout (tmux/IDE-style) where plots fill the viewport
Panel logic In-editor node-graph flow editor (triggers → actions, dialogs) that runs client-side in view mode
Control logic Server-side always-on flow graphs with cron/alarm triggers and Lua blocks
Configuration manager Versioned configuration sets (typed signal schemas, grouped) and instances (values) with validation, array/CSV editing, apply-to-signals, and JSON import/export
Version history & diff Git-style history for panels, synthetic signals, control logic and config sets/instances: view, fork, promote any revision, with unified / side-by-side diff
Local variables Panel-scoped state variables for set-points, toggles and counters used by logic
Historical data EPICS Archive Appliance integration via REST; time range picker in UI
Synthetic signals Compose, filter, and transform signals via a wizard or visual node-graph editor (gain, offset, moving average, lowpass, highpass, derivative, integral, clamp, formula); panel/user/global visibility scopes
Access control Identity via trusted proxy header; per-user global level (write/read-only/no-access); per-panel ownership + sharing; nested folders; optional logic-editor allowlist
Multi-client Subscriptions are multiplexed — N clients share one upstream connection per signal
Signal discovery Filter/search, CSV import, manual add, Channel Finder proxy
Observability Prometheus-format metrics at /metrics
Single binary Frontend assets embedded at build time — no web server needed

Quick Start

Prerequisites

  • Go 1.22+ — the only build dependency (the frontend is bundled by a pure-Go esbuild wrapper)
  • EPICS Base (libca) — only required for the epics build tag; the stub and synthetic data sources work without it

Build

# Full build — bundles the frontend then compiles the binary
make all

The binary is written to dist/uopi.

Run

./dist/uopi                    # uses default config (stub data source only)
./dist/uopi --config uopi.toml # explicit config file

Then open http://localhost:8080 in your browser.

SSH tunnel example:

ssh -L 8080:localhost:8080 user@controlhost
# then open http://localhost:8080 locally

Configuration

Create uopi.toml (all fields are optional — shown values are defaults):

[server]
listen      = ":8080"
storage_dir = "./interfaces"  # where interface XML, ACL and logic data are stored

# Identity & access control (all optional)
trusted_user_header = ""      # HTTP header carrying the proxy-authenticated user
default_user        = ""      # identity used when the header is absent (LAN/dev)
# logic_editors     = []      # restrict who may edit panel/control logic (users or groups)

# [[server.blacklist]]        # downgrade a user: level = "readonly" or "noaccess"
# user = "guest"
# level = "readonly"

# [[groups]]                  # named user sets, referenced by panel sharing
# name    = "operators"
# members = ["alice", "bob"]

[datasource.epics]
enabled           = false    # requires build with -tags epics
ca_addr_list      = ""       # overrides EPICS_CA_ADDR_LIST if non-empty
archive_url       = ""       # EPICS Archive Appliance base URL, e.g. http://archiver:17665
channel_finder_url = ""      # EPICS Channel Finder base URL (optional)

[datasource.synthetic]
enabled = true

All settings can be overridden with environment variables using the UOPI_ prefix and double underscores for nesting:

UOPI_SERVER_LISTEN=":9090" UOPI_DATASOURCE_EPICS_ENABLED=true ./dist/uopi

Building with EPICS Support

The EPICS data source uses CGo bindings to libca. First set up the EPICS environment variables, then:

export EPICS_BASE=/path/to/epics/base
export CGO_CFLAGS="-I$EPICS_BASE/include -I$EPICS_BASE/include/os/Linux"
export CGO_LDFLAGS="-L$EPICS_BASE/lib/linux-x86_64 -lca -lCom"

make backend-epics

Then enable it in uopi.toml:

[datasource.epics]
enabled = true

API

The REST API is available under /api/v1. Key endpoints:

Method Path Description
GET /api/v1/datasources List registered data sources
GET /api/v1/signals?ds=<name> List signals for a data source
GET /api/v1/signals/search?q=<query> Search signals across all sources
GET /api/v1/channel-finder?q=<query> Proxy to EPICS Channel Finder
GET/POST /api/v1/interfaces List or create HMI interfaces
GET/PUT/DELETE /api/v1/interfaces/{id} Read, update, or delete an interface
POST /api/v1/interfaces/{id}/clone Duplicate an interface
POST /api/v1/interfaces/reorder Reorder panels / move them between folders
GET/PUT /api/v1/interfaces/{id}/acl Read or set a panel's sharing rules
GET/POST /api/v1/folders List or create panel folders
PUT/DELETE /api/v1/folders/{id} Rename/reparent or delete a folder
GET/POST/DELETE /api/v1/synthetic Manage synthetic signal definitions
GET/POST /api/v1/controllogic List or create server-side control-logic graphs
GET/PUT/DELETE /api/v1/controllogic/{id} Read, update, or delete a control-logic graph
GET/POST /api/v1/config/sets List or create configuration sets (schemas)
GET/PUT/DELETE /api/v1/config/sets/{id} Read, update, or delete a config set
GET/POST /api/v1/config/instances List or create configuration instances (values)
GET/PUT/DELETE /api/v1/config/instances/{id} Read, update, or delete a config instance
POST /api/v1/config/instances/{id}/apply Write an instance's values to their target signals
GET /api/v1/config/{sets|instances}/diff Structural diff between two revisions
GET /api/v1/{interfaces|synthetic|controllogic|config/sets|config/instances}/{id}/versions List revisions; …/{version} fetches one
POST …/{id}/versions/{v}/promote Promote a revision to current
POST …/{id}/versions/{v}/fork Fork a revision into a new document
GET /api/v1/me Caller identity, access level, groups, logic-edit permission
GET /api/v1/usergroups List configured users and groups (for sharing)
GET /metrics Prometheus-format server metrics
GET /healthz Health check

WebSocket live data is at ws://<host>/ws. See docs/TECHNICAL_SPEC.md for the message protocol.


Development

# Build frontend only (output → web/dist/)
make frontend

# Build backend only (frontend must already be built)
make backend

# Run the server directly without a binary (uses stub data source)
go run ./cmd/uopi

# Run all tests
make test

# Run tests with race detector
make race

# Run benchmarks
make bench

# Static analysis
make lint

# Clean build artefacts
make clean

Observability

The /metrics endpoint exposes Prometheus-format counters and gauges:

uopi_uptime_seconds          — seconds since start
uopi_ws_connections          — current open WebSocket connections
uopi_signal_subscriptions    — current unique upstream signal subscriptions
uopi_ws_messages_in_total    — total messages received from clients
uopi_ws_messages_out_total   — total messages sent to clients
uopi_write_ops_total         — total signal write operations
uopi_history_requests_total  — total historical data requests

Scrape with any Prometheus-compatible tool or view directly in the browser.


Docs

Document Description
docs/FUNCTIONAL_SPEC.md User-facing feature specification
docs/TECHNICAL_SPEC.md Architecture, WebSocket protocol, API design
docs/WORK_PLAN.md Phased development plan with milestones

Release

Releases are built with goreleaser:

goreleaser release --clean

See .goreleaser.yaml. Note that release binaries are built without EPICS support (CGO_ENABLED=0) for maximum portability. Build from source with -tags epics for CA connectivity.


License

TBD

S
Description
uOPI: light, fast, web based OPI
Readme 15 MiB
Languages
Go 47.8%
TypeScript 43.8%
CSS 6.9%
C 0.5%
Shell 0.4%
Other 0.6%