跳转到内容

BMCLI web

Reference version: BMCLI 1.6.3. Command names, parameters and machine-readable fields retain their source spelling.

Host the packaged engineering console and BUSMUST Automation API v1 inside the BMCLI daemon. The service exposes typed bench and device snapshots, channel lifecycle and statistics, CAN/CAN FD/LIN message send, cursor-based raw history, SSE, binary WebSocket frames, DBC signal decode plans, logging/replay/gateway lifecycle, bounded firmware-check jobs, and runtime command discovery. It does not execute arbitrary command lines. /api/v1/operations reports every current CLI operation, explicit permission/execution policy, parameter metadata, and whether its typed HTTP handler has been migrated.

The packaged Console polls health and marks retained signal samples stale when the Web service is unavailable. Raw SSE, raw WebSocket, and signal SSE keep independent connection handles, cursors, status, gap diagnostics, and Stop controls; restarting one does not replace another. Refresh reloads devices, open channels, databases, DBC message catalogs, signal plans, runtime OpenAPI, operations, and metrics. If a server-local signal plan disappeared after a Web restart, the Console marks it expired and offers an in-page rebuild using the retained channel/database/message/history fields. Message Send validates its visible fields against the typed request contract before issuing a network request, while Advanced mode only relaxes the channel-selector source check.

Terminal window
# Default: loopback only, packaged console, no token required
bmcli web start --listen=127.0.0.1:8080 --format=json
# Explicit project Web root
bmcli web start --listen=127.0.0.1:8080 --web-root=<directory> --format=json
# Debug diagnostics appended to a file
bmcli web start --log-level=debug --log-file=web-debug.log --format=json
# Non-loopback plain HTTP requires authentication and explicit risk acknowledgement
bmcli web start --listen=0.0.0.0:8080 --token=<secret> --allow-insecure-http --format=json

web start starts the daemon when needed. Open hardware channels with daemon start --channel=... or channel open before using hardware endpoints. The default history capacity is 8192 events and can be changed with --history-capacity=<count>.

Web diagnostics default to --log-level=info and stderr. The accepted levels are exactly lowercase off, error, info, and debug: off emits nothing; error records startup/runtime errors and completed 4xx/5xx requests; info also records lifecycle events and every completed request with method, path without its query, status, and nonnegative duration; debug also reports route hit/miss and sanitized error code/message detail. --log-file=<path> appends to a file instead of stderr; a relative path is resolved from the daemon start working directory. If the file cannot be opened, Web startup fails without falling back to stderr. Successful start and running/stopped status output report the effective log_level and log_destination; file destinations are absolute and stderr is reported with that stable name. These options do not introduce a project_root; existing Web-root and daemon working-directory ownership remain unchanged.

Endpoint Purpose
GET /api/v1/info Product, build, API, and service identity
GET /api/v1/health Daemon, Web, and channel-broker health
GET /api/v1/capabilities Transports, resources, limits, and security defaults
GET /api/v1/openapi.json Packaged and regression-gated OpenAPI 3.1 contract
GET /api/v1/operations[/{operation_id}] Runtime CommandRegistry and HTTP migration policy
GET /api/v1/bench Selected project/global bench snapshot
GET /api/v1/devices Local physical analyzers, deduplicated across channels
POST /api/v1/devices/{selector}/firmware-check Queue a non-disruptive firmware release check
GET /api/v1/jobs[/{job_id}] List or inspect bounded asynchronous jobs
GET/POST /api/v1/channels List or open daemon channels
GET/PATCH/DELETE /api/v1/channels/{selector} Inspect, configure, or close a daemon channel
GET /api/v1/channels/{selector}/stats Hardware counters, rates, bus state, and broker retention
GET/POST /api/v1/databases List or load typed database resources inside the project working root
GET/DELETE /api/v1/databases/{name} Inspect or unload one database resource; DBC inspection includes bounded message metadata
GET/POST /api/v1/tx-tasks List or add a channel TX task/LIN slave response
DELETE /api/v1/tx-tasks/{task_id} Remove one channel TX task
GET/POST /api/v1/routes List or add a hardware message route
DELETE /api/v1/routes/{route_id} Remove one hardware message route
POST /api/v1/messages Typed CAN/CAN FD/LIN send or LIN transaction
GET /api/v1/messages/history Cursor-based raw history with explicit expiry
GET /api/v1/messages/stream SSE raw-message stream with gap events
GET /api/v1/messages/ws bmcli.frames.v2 BMF2 binary stream
GET /api/v1/signals Active DBC decode plans
POST /api/v1/signals/plans Create a bounded DBC signal plan
DELETE /api/v1/signals/plans/{plan_id} Delete a signal plan
GET /api/v1/signals/latest Latest decoded signal sample
GET /api/v1/signals/history Cursor-based decoded signal history
GET /api/v1/signals/stream SSE decoded-signal stream
GET/POST/DELETE /api/v1/logging Inspect, start, or stop project-confined ASC logging
GET/POST/DELETE /api/v1/replay Inspect, start, or stop project-confined ASC/BLF replay
GET/POST/DELETE /api/v1/remote-bmapi Inspect, start, or stop the remote-BMAPI gateway

The exact request fields, units, limits, errors, query parameters, and WebSocket layout are authoritative in /api/v1/openapi.json. Read it at runtime instead of copying this table into an application. Percent-encode / when a stable SN/port selector is placed in a path segment, for example 10356%2F0; query parameters and JSON fields keep the ordinary 10356/0 form. POST /api/v1/execute is not a shell: v1 accepts only the migrated one-token version operation. Use dedicated resource endpoints for hardware work.

Channel open and config intentionally use different request schemas: ChannelOpenRequest requires channel, while ChannelConfigRequest obtains the selector from the path and accepts one setter group. Message type is one of data, remote, master-write, master-read, or sync-break; the runtime rejects values outside that OpenAPI enum. The Console Typed API picker and body template are generated from the runtime OpenAPI document rather than a copied operation list.

Failed Web message sends preserve the submitted selector in error.details.channel. Logical networks report selector_kind=network and either network_unbound or the resolved physical selector; valid but unopened physical/name selectors report channel_not_open; malformed SN/port or UID/port forms report invalid_channel_selector. A failed lookup never substitutes numeric daemon slot zero for the caller’s selector.

The raw WebSocket endpoint requires and selects bmcli.frames.v2 and emits only BMF2. A v1-only, missing, or unknown frame subprotocol is rejected with HTTP 400 unsupported_websocket_subprotocol before the 101 upgrade. When v2 and v1 are both offered, the server selects only v2. There is no BMF1 output, downgrade, dual-stack mode, or compatibility switch. Each WebSocket binary message is one BMF2 event: a 64-byte unsigned big-endian header followed by exactly payload_length bytes, for a total length of 64 + payload_length. The fixed offsets are magic[0:4], version@4, header_length@5, bus@6, event_kind@7, channel@8:u16, payload_length@10, dlc@11, id@12:u32, flags@16:u32, status@20:u32, event_id@24:u64, source_sequence@32:u64, stream_epoch@40:u64, timestamp_us@48:u64, hardware_sequence@56:u16, filter_hit@58, checksum@59, zero reserved@60:u32, and payload at 64. event_kind is 1 for rx_frame and 2 for tx_complete.

One channel PATCH may contain only one hardware setter group. CAN nominal/data timing is one group and LIN version/checksum is one group; mode, termination, pull-up, bitrate, and power are separate groups. Valid same-value updates are idempotent. This prevents a later BMAPI setter failure from leaving an undisclosed partially applied multi-field request.

All ordinary daemon receive consumers share one RxBroker owner per channel. message recv, software logging, gateway forwarding, Web history, SSE, WebSocket, and DBC signal decoding therefore use independent cursors instead of competing calls to BM_Read. History expiry returns 409 cursor_expired with error.details.oldest_available and newest_available; SSE and WebSocket streams emit an explicit gap event with the same recovery bounds. A resumable client continues from oldest_available - 1, de-duplicates by sequence, and must not silently replace an expired cursor with now.

For /api/v1/signals/latest and /api/v1/signals/history, both plan and signal are required: missing/empty values return HTTP 400 invalid_argument; a valid request with no sample returns 404. History uses after=<sequence>, not cursor; omitted after means 0 and can therefore return 409 after ring retention has advanced. Acknowledge the gap and continue with after=oldest_available-1; after=newest_available deliberately drops retained history and waits for later samples.

Relative web start --web-root paths are resolved from the invoking CLI’s working directory before being handed to the daemon.

  • Default bind is 127.0.0.1; CORS is disabled.
  • Any non-loopback bind requires --token; API callers use Authorization: Bearer <token>. WebSocket clients may use bmcli.token.<token> as a second subprotocol.
  • Non-loopback bind also requires the presence-only --allow-insecure-http acknowledgement. This option does not weaken loopback defaults or add encryption; it prevents an accidental remote bind from looking secure merely because a token was supplied.
  • The current embedded server uses plain HTTP. A bearer token authenticates a caller but does not encrypt headers, payloads, bus traffic, or the token itself. Keep loopback as the normal deployment. Use a non-loopback listener only on a trusted isolated engineering network with host firewall rules, or place it behind an approved HTTPS reverse proxy; do not expose it directly to an untrusted LAN or the Internet.
  • Linux packages include an audited Nginx profile at share/bmcli/packaging/https/. It terminates TLS, preserves SSE/WebSocket streaming, and proxies only to the BMCLI loopback listener. Certificate validation must pass normally; do not use browser security bypasses.
  • Static files are read-only and reject path traversal.
  • Diagnostic records never contain bearer tokens, Authorization or Cookie values, raw query strings, request bodies, or the configured start token. Necessary dynamic error detail is logged as [redacted]. Control characters are escaped so each event remains exactly one physical log record.
  • CSP constrains executable script sources and reduces injected inline-script execution. The current response policy is script-src 'self' and style-src 'self' 'unsafe-inline': browser JavaScript must be served as an external file from the Web root, while inline style remains allowed. Prefer external JavaScript and CSS assets for generated dashboards.
  • Request body limit is 64 KiB; response limit is 2 MiB; simultaneous client, SSE, and WebSocket limits are reported by capabilities.
  • Treat Web message send and signal-plan creation as active bench operations. Apply the same authorization and cleanup rules as direct BMCLI commands.
Terminal window
bmcli web status --format=json
bmcli web stop --format=json

web stop releases the listener and stream clients but leaves a pre-existing daemon and its open channels running. web status always reports default_listen (127.0.0.1:8080). While running, listen_source=effective and listen, configured_listen, and effective_listen identify the active endpoint. While stopped, listen_source=default, listen matches the next no-argument web start, effective_listen is null, and configured_listen retains the last successful explicit configuration for diagnostics. Stopped status also retains the last effective diagnostic level and destination.


Source of truth: BMCLI 1.6.3 repository documentation. Run bmcli help <category> <action> --format=json for the exact contract of the installed version.