BMCLI Modbus RTU, ASCII, and TCP
Reference version: BMCLI 1.6.3. Command names, parameters and machine-readable fields retain their source spelling.
The modbus command category is the Modbus Client interface. Gateway projects
also support a local TCP/RTU/ASCII Server mirror. The Client supports FC01,
FC02, FC03, FC04, FC05, FC06, FC15, FC16, FC20, FC21, and FC24. Addresses are
always zero-based protocol addresses; a vendor display reference such as 40001
must be converted according to that vendor’s documentation.
All modbus commands produce structured data and require --format=json or
--format=jsonl; use JSON for bounded commands and REST responses.
Use runtime Help as the exact option contract:
bmcli help modbus --format=jsonbmcli help modbus read --format=jsonbmcli help modbus resource read --format=jsonbmcli help modbus poll start --format=jsonExplicit raw access accepts either a logical --channel imported into the
bench or a complete endpoint. A TCP example is:
bmcli modbus read --transport=tcp --host=127.0.0.1 --unit-id=1 --table=holding-registers --address=0 --count=2 --format=jsonSerial endpoints require --transport=rtu|ascii, --port, --baud,
--data-bits, --parity, --stop-bits, and --unit-id. RTU requires eight
data bits. BMCLI validates CRC/LRC, Unit ID, function code, transaction ID,
response length, exception responses, timeout, and protocol quantity limits.
Read operations may be retried by a supervising application; writes are not
automatically retried because a timeout leaves completion ambiguous.
modbus status only opens the selected transport. Its
transport_open=true, slave_checked=false result does not prove that a Unit ID
responds; issue a bounded read of a known address for that check.
EdgeX profiles and logical devices
Section titled “EdgeX profiles and logical devices”BMCLI reads the Linux Foundation EdgeX Modbus Device Profile subset needed for
deviceResources and deviceCommands, including value type, read/write access,
scale, offset, unit, range, mappings, byte/word order, and Modbus attributes.
Unknown YAML/JSON fields are skipped. This is a tolerant read-only importer,
not an EdgeX editor.
The official EdgeX table spelling is DISCRETES_INPUT; the older
DISCRETE_INPUTS spelling is accepted only as a compatibility alias.
EdgeX Device Definitions may bind modbus-tcp, modbus-rtu, or
modbus-ascii. Command writes accept an exact raw mapping key or a unique,
case-sensitive published label; an exact raw key takes precedence. Reads retain
the raw key and engineering value and add mapped when a mapping matches.
Label ambiguity, an unknown label/type mismatch, and range failures are
validated for every operation before opening the transport, so they send zero
requests. Mapping keys remain exact raw text through integer encoding, including
signed and unsigned 64-bit values beyond IEEE-754’s exact integer range. Limits
still apply to the derived engineering value, and byte/word ordering is applied
once to the exact raw value.
For modbus-tcp, Address contains only the host (a hostname, IPv4 address,
or bare IPv6 address) and Port is a required integer in 1..65535.
Address:port and [IPv6]:port forms are rejected at import with a field-level
diagnostic instead of being accepted and later combined with another/default
port. BMCLI does not auto-correct this invalid EdgeX shape.
bmcli database load --file=boiler-profile.yaml --type=modbus-edgex --name=boiler --format=jsonbmcli bench import --file=devices.yaml --source-format=edgex-modbus --device=Boiler-RTU --format=jsonbmcli bench import --file=devices.yaml --source-format=edgex-modbus --device=Boiler-RTU --apply --format=jsonbmcli modbus resource read --database=boiler --resource=Temperature --channel=boiler-rtu --format=jsonbench import is dry-run by default and never guesses a COM/tty path, host,
Unit ID, device selection, or collision replacement. Use --replace only with
an explicitly reviewed --apply operation. Profiles share the generic typed
database lifecycle and unload with database unload.
Writing a resource with EdgeX access W sends exactly one write and does not
attempt a readback that the profile declares unavailable. Access RW retains
write verification. If a multi-resource command fails after earlier writes,
the structured error identifies failed_resource, failed_operation,
completed_operations, and whether a write may already have completed; callers
must not blindly retry the whole command.
Polling, REST, and Dashboard
Section titled “Polling, REST, and Dashboard”A daemon-owned poll job reads one EdgeX resource or command immediately and
then at a requested interval. Each job retains at most 256 complete dynamically
sized samples and 1 MiB in memory, and reports sequence, quality,
freshness/stale state, errors, gaps, and missed deadlines. The daemon owns one
persistent session per physical endpoint; poll jobs, one-shot CLI operations,
and Web calls serialize transactions through it. A different configuration for
an already-owned physical endpoint fails explicitly. The session reconnects
after an I/O/protocol failure. --on-change suppresses unchanged good values
but retains errors.
bmcli modbus poll start --job=boiler-temp --interval=500 --database=boiler --resource=Temperature --channel=boiler-rtu --format=jsonbmcli modbus value latest --job=boiler-temp --format=jsonbmcli modbus value history --job=boiler-temp --count=100 --format=jsonbmcli modbus value history --job=boiler-temp --after=120 --count=100 --format=jsonbmcli modbus poll stop --job=boiler-temp --format=jsonThe typed Web API exposes raw operations, EdgeX resources/commands, poll
lifecycle, latest/history, and SSE updates under /api/v1/modbus. The bundled
engineering page provides endpoint inspection, polling, value, quality and
history visualization. History returns oldest_sequence, latest_sequence,
next_after, and gaps. SSE uses the sample sequence as its event ID, drains
every retained sample in order, resumes from Last-Event-ID, and emits an
explicit gap event if that cursor has expired. Runtime OpenAPI is
authoritative. Poll state and history are intentionally process-local and are
deleted when stopped or when the daemon exits; durable storage belongs to a
surrounding application service.
Source of truth: BMCLI 1.6.3 repository documentation. Run bmcli help <category> <action> --format=json for the exact contract of the installed version.