# MTConnect agent for LinuxCNC — demo config First-class MTConnect support for LinuxCNC: a userspace, non-realtime agent that exposes machine **status**, a rich **kinematic description**, and **tool data** over MTConnect. It ships an embedded HTTP agent (no external dependency) and can optionally publish over the standard MTConnect **MQTT** binding. The `/probe` response carries enough kinematic detail for an external tool (e.g. a FreeCAD Path plugin) to auto-configure a machine. This directory is a demo sim config. The agent itself installs with LinuxCNC (`bin/mtconnect-agent`, package `lib/python/mtc`, assets under `share/linuxcnc/mtconnect`). For the full reference see the `mtconnect-agent(1)` man page and the `[MTCONNECT]` section of the INI configuration chapter. ## Quick start ```sh # From this directory: linuxcnc example.ini # launches the sim + the MTConnect agent # In another terminal: curl http://localhost:5000/probe # MTConnectDevices (structure + kinematics) curl http://localhost:5000/current # latest value of every DataItem curl http://localhost:5000/sample?from=1&count=100 curl http://localhost:5000/assets # CuttingTool assets (tool table) ``` You can inspect the generated device model without launching LinuxCNC (after sourcing `scripts/rip-environment` in a RIP build, or with LinuxCNC installed): ```sh mtconnect-agent --dump-probe example.ini mtconnect-agent --dump-probe ../vismach/5axis/table-rotary-tilting/xyzac-trt.ini ``` ## Enabling it in your own config Add a few lines to your INI. The device model is generated automatically from `[TRAJ]`, `[KINS]`, `[AXIS_*]` and `[JOINT_*]`. ```ini [MTCONNECT] ENABLE = 1 DEVICE_NAME = my_mill UUID = linuxcnc-my-mill-0001 HTTP_PORT = 5000 # HTTP_BIND defaults to 127.0.0.1 (loopback); set 0.0.0.0 to expose on the LAN. # HTTP_BIND = 127.0.0.1 # TRANSPORT: comma list of http, mqtt, shdr (no inline comments in INI values) TRANSPORT = http SAMPLE_HZ = 10 # MQTT_BROKER = localhost # MQTT_PORT = 1883 # MQTT_PREFIX = MTConnect ``` Load the agent from a HAL file (see `mtconnect.hal`): ``` loadusr -W mtconnect-agent ``` `-W` waits until the component is ready; the INI comes from `$INI_FILE_NAME`. Loading it in the HAL file (rather than `[APPLICATIONS]`) makes the status pins (`active`, `connected`) available for linking. ## What is exposed | Endpoint | Content | |------------|---------| | `/probe` | Device structure: Controller/Path, Axes (Linear/Rotary + Motion), spindle, and the `x:Kinematics` extension | | `/current` | Latest value of every DataItem (execution, mode, positions, spindle, feed, tool) | | `/sample` | Sequence-numbered observation history (`?from=&count=`) | | `/assets` | Tool table as `CuttingTool` assets (location, diameter, length offsets) | ### LinuxCNC → MTConnect mapping (`linuxcnc.stat()`) | MTConnect DataItem | Source | |---|---| | `EMERGENCY_STOP` | `task_state` | | `CONTROLLER_MODE` | `task_mode` | | `EXECUTION` | `interp_state`, `task_paused` | | `PROGRAM`, `LINE_NUMBER` | `file`, `motion_line` (executing line, not interp read-ahead) | | `PATH_FEEDRATE` (+ OVERRIDE) | `current_vel`, `feedrate` | | `POSITION` / `ANGLE` (ACTUAL/COMMANDED) | `actual_position`, `position` | | `ROTARY_VELOCITY`, `ROTARY_MODE`, `DIRECTION` | `spindle[0]` | | `TOOL_NUMBER`, `TOOL_ASSET_ID` | `tool_in_spindle` | | `ASSET_CHANGED` | tool change detection | | `CuttingTool` assets | `tool_table` | ## The kinematic description (`x:Kinematics`) Standard MTConnect models axes as `Linear`/`Rotary` components with `Motion` elements (`PRISMATIC`/`REVOLUTE`, direction vector). LinuxCNC specifics that do not map cleanly are carried in a versioned extension namespace `urn:linuxcnc:mtconnect:1` — the primary contract for auto-configuration: ```xml ``` A FreeCAD plugin reads the standard `Axes`/`Motion` tree, or the compact `x:Kinematics` block, to create/configure a machine: axis list and type, travel limits, home positions, kinematics module/type, and the joint↔axis map. ## Solid models (geometry) A standard MTConnect twin viewer (e.g. the one at demo.mtconnect.org, or TrakHound) renders a machine from `/probe` alone: geometry is **referenced, never streamed**. The device model carries `` elements pointing to external mesh files, plus `` and a `` chain; the viewer fetches each mesh once (from the agent's `/models/`) and animates it using the streamed positions. LinuxCNC bundles no viewer and no JavaScript — this is plain, standards-compliant MTConnect. ### Zero-config geometry (`MODEL_AUTO`) ```ini [MTCONNECT] MODEL_AUTO = 1 ``` The agent generates simple placeholder **box** meshes for the base and each axis straight from the travel limits and serves them from memory — any machine gets a functional twin with **no mesh files**. This is what the example config uses. ### Real geometry (per-link meshes) Supply your own meshes (STL / OBJ / glTF) for fidelity: ```ini [MTCONNECT] MODEL_DIR = models ; base dir for relative paths (default: INI dir) MODEL_BASE = frame.stl ; static frame / column (device-level SolidModel) MODEL_X = x_table.stl ; link that moves with X MODEL_Y = y_saddle.stl MODEL_Z = spindle.stl MODEL_SPINDLE = spindle.stl ``` Author each mesh in **millimetres** (MTConnect's canonical unit — the SolidModel element carries no per-mesh unit) in the machine frame at the all-axes-zero pose. An explicit `MODEL_` overrides the generated box for that link, so files and `MODEL_AUTO` can be mixed. ### Topology and direction (both modes) These describe the mechanics and are **not** derivable from a trivkins INI: ```ini MODEL_CHAIN = Y X Z ; nesting order of the moving links (base -> tip) MODEL_PARENT_Z = BASE ; branch: Z (quill/tool) hangs off the base, not X/Y MODEL_INVERT = X Y ; work-carrying links move opposite the reported coord ``` The agent then serves each mesh at `GET /models/`, emits a device-level `` for the base and a per-axis `` in each axis's ``, and emits `` (WORLD → MACHINE) plus a `` chain (`parentIdRef`) so the twin nests transforms correctly. ### Viewing the twin The agent serves the geometry but **bundles no viewer** — rendering is left to a standard MTConnect client, so no third-party JavaScript lives in LinuxCNC. Two paths: - **A standard MTConnect twin viewer (recommended).** Point one at the agent and it renders the machine from `/probe` + `/models/` with zero extra setup: the demo viewer at , TrakHound, or cppagent's demo twin. Expose the agent first with `[MTCONNECT]HTTP_BIND = 0.0.0.0` (it defaults to loopback only) and give the viewer `http://:5000`. - **Self-host a small viewer.** An earlier revision of this config shipped a ~12 KB three.js viewer (`twin.html`) that was removed from the tree to keep third-party JS out of core. It still works against this agent — it fetches `/probe` and `/current` and loads the `/models/` meshes. To run it yourself, recover it from git history (`git show :share/linuxcnc/mtconnect/twin.html`), repoint its three.js import map at a CDN or a local `libjs-three`, and serve it same-origin as the agent (e.g. behind a small reverse proxy, since the relative `fetch` calls assume one origin). ## Using the official cppagent instead of the embedded agent Put `shdr` in `TRANSPORT` and the agent acts as an SHDR adapter (default port 7878), streaming `|id|value` lines to an external cppagent. Configure that cppagent with a `Devices.xml`, which the generated `/probe` document doubles as: ```sh mtconnect-agent --dump-probe example.ini > Devices.xml ``` The `dataItemId`s in the SHDR stream match the ids in that `Devices.xml`. ## MQTT With `mqtt` in `TRANSPORT` and `python3-paho-mqtt` installed, the agent publishes the standard (vendor-neutral) MTConnect MQTT topics: `/Probe/` (retained), `/Current/`, `/Sample/`, `/Asset//`. A consumer discovers the whole device from the retained Probe topic. **Home Assistant** is not part of the core agent (its MQTT Discovery format is HA-specific). An optional bridge, `contrib/mtconnect-ha-bridge`, reuses the device model to publish HA discovery; configure it with arguments so no HA key touches the machine INI: ``` loadusr -W mtconnect-ha-bridge --broker=[HA]BROKER --username=[HA]USER --password=[HA]PASSWORD ``` ## Layout (installed) ``` src/hal/user_comps/mtconnect-agent.py entry point -> bin/mtconnect-agent lib/python/mtc/ the agent package: ini_reader.py INI access (linuxcnc.ini, with offline fallback) kinematics.py build the kinematic model from the INI observations.py shared DataItem registry (keeps probe and streams in sync) device_model.py /probe MTConnectDevices document (+ CLI --dump-probe) lcnc_source.py live status + tool table from linuxcnc.stat() models.py solid-model config + served mesh registry (SolidModel geometry) streams.py /current, /sample buffer + XML; /assets XML agent.py transport-agnostic agent core (document builders) http_agent.py embedded HTTP server mqtt_agent.py optional MQTT publisher (vendor-neutral MTConnect binding) share/linuxcnc/mtconnect/mtconnect-linuxcnc-1.xsd extension schema configs/sim/axis/mtconnect/ this demo config + tests contrib/mtconnect-ha-bridge opt-in Home Assistant MQTT-discovery bridge contrib/ha.py HA discovery helper (used by the bridge) ``` ## Testing ```sh . scripts/rip-environment # so mtc is importable and bin/ is on PATH python3 test_mtc.py # offline suite (no running LinuxCNC required) python3 validate_schemas.py # validate the documents against the MTConnect XSDs # (needs the 'xmlschema' package) ``` `test_mtc.py` covers kinematics mapping, probe↔registry consistency (3- and 5-axis), the observation buffer + streams, assets, the live HTTP endpoints, and (when `xmlschema` is available) schema validation of all four documents. ## Custom HAL pins Expose any HAL pin/signal as a data item with `HAL_ITEM` lines (read via `hal.get_value`, no HAL wiring): ```ini [MTCONNECT] HAL_ITEM = pin=spindle.0.load, id=spindle_load, type=LOAD, units=PERCENT, component=spindle HAL_ITEM = pin=hm2_5i25.temp, id=board_temp, type=TEMPERATURE, units=CELSIUS ``` Standard MTConnect SAMPLE types only (LOAD, TEMPERATURE, PRESSURE, VOLTAGE, AMPERAGE, FREQUENCY, ANGLE, VELOCITY, TORQUE, …). `component=` hosts it under a generic `Sensor` (default) or an existing component (spindle/controller/path/an axis). Unsupported types are skipped with a warning. See `mtconnect-agent(1)`. ## Status Complete and packaged for the build: the HTTP transport, HAL component and schema-valid documents; the vendor-neutral MQTT binding plus the optional Home Assistant bridge contrib; `SolidModel` geometry under `/models/` for any standard MTConnect twin viewer; and the SHDR adapter for an external cppagent. Realtime servo-rate data is explicitly out of scope.