Skip to main content

Governed, vendor-neutral OT data tap + intelligent troubleshooting for AI agents (OPC-UA / Modbus / S7comm / Mitsubishi MC / MTConnect / MQTT-Sparkplug) with a built-in governance harness (audit, budget, risk tiers, MOC)

Project description

OT-AIops

Governed, vendor-neutral industrial data tap + intelligent troubleshooting for AI agents — across OPC-UA, Modbus-TCP, S7comm, Mitsubishi MC, MTConnect, and MQTT/Sparkplug B.

OT-AIops is the OT/industrial member of AIops-tools. It is a factory-level, vendor-neutral, governed data tap that lets an AI agent safely read industrial control systems across many field protocols, plus a cross-protocol intelligence layer that localizes "no data" breaks, analyzes alarm floods (ISA-18.2), and ranks unhealthy tags. Read-first by design; the few write/command paths are OT-dangerous and gated by MOC discipline. Every tool runs through a vendored governance harness (audit / budget / risk-tier / undo).

⚠️ Preview / v0.1.0 — validated against an in-process OPC-UA simulator, mocked Modbus/S7/Mitsubishi clients, static MTConnect XML fixtures, and synthetic MQTT/Sparkplug payloads. NOT tested against live PLCs / SCADA / brokers. See Safety.

Why

OT is exactly where you want an agent on a tight leash: read first, never blind-write. OT-AIops is the safe, neutral read wedge — one package, one MCP server, many protocols — with governance and an intelligence layer that turns raw reads into actionable diagnoses.


Consolidated capability matrix

Protocol Tool Operation R/W risk_tier Returns (key fields)
OPC-UA opcua_server_info server status R low state, product_name, namespaces
OPC-UA opcua_browse browse node tree R low [{node_id, browse_name, depth}]
OPC-UA opcua_read_node read one node R low value, datatype, source_timestamp, good
OPC-UA opcua_read_many batch read R low [{node_id, value, ...}]
OPC-UA opcua_subscribe_sample bounded sample R low {collected, samples[]}
OPC-UA opcua_read_alarms alarm surfacing R low {active_alarms[], active_count}
OPC-UA health_summary threshold classify R low {overall, counts, offenders[]}
OPC-UA anomaly_scan stddev outliers R low {mean, stddev, outliers[]}
Modbus modbus_read_holding FC03 R low {raw_registers, decoded[]}
Modbus modbus_read_input FC04 R low {raw_registers, decoded[]}
Modbus modbus_read_coils FC01 R low {bits[]}
Modbus modbus_read_discrete FC02 R low {bits[]}
Modbus modbus_health_summary threshold classify R low {overall, counts, offenders[]}
S7comm s7_cpu_info CPU id + run/stop R low {cpu_status, cpu_info}
S7comm s7_read_area read DB/M/I/Q R low {items:[{address, value}]}
S7comm s7_read_db read data block R low {items:[{address, value}]}
S7comm s7_read_many batch addresses R low {items:[{address, value}]}
S7comm s7_write_db write data block W high/MOC {before, written, _undo_id}
Mitsubishi MC mc_cpu_status CPU type R low {cpu_type, cpu_code}
Mitsubishi MC mc_read_words word devices R low {words[]}
Mitsubishi MC mc_read_bits bit devices R low {bits[]}
Mitsubishi MC mc_read_many random read R low {words[], dwords[]}
Mitsubishi MC mc_write_words write words W high/MOC {before, written, _undo_id}
MTConnect mtconnect_probe device model R low {devices:[{components:[{data_items}]}]}
MTConnect mtconnect_current latest values R low {observations[]}
MTConnect mtconnect_sample bounded stream R low {observations[]}
MTConnect mtconnect_assets assets R low {assets[]}
MTConnect mtconnect_oee_snapshot OEE inputs R low {availability, execution, verdict}
MQTT/Sparkplug mqtt_read_topic bounded read R low {messages:[{topic, payload}]}
MQTT/Sparkplug sparkplug_subscribe_sample bounded SpB sample R low {samples:[{sparkplug, payload}]}
MQTT/Sparkplug sparkplug_node_list node discovery R low {nodes:[{group_id, edge_node_id, devices}]}
MQTT/Sparkplug uns_browse topic-tree browse R low {topics[], tree{}}
MQTT/Sparkplug mqtt_publish publish/command W high/MOC {published_bytes, applied}
Diagnostics diagnose_dataflow localize no-data R low {verdict, diagnosis, hops[]}
Diagnostics alarm_bad_actors ISA-18.2 flood R low {flood_verdict, top_offenders[]}
Diagnostics tag_health offender ranking R low {overall, offenders[]}
Diagnostics historian_health gap/flatline R low {verdict, gaps[]}
Self protocols_supported capability map R low {protocols[], diagnostics[]}
Roadmap ethernetip_status Rockwell stub R low {implemented:false, suggested_dependency}
Roadmap ethercat_status EtherCAT stub R low {implemented:false, suggested_dependency}

40 tools = 33 read · 3 write (MOC) · 4 diagnostics. Run protocols_supported() (or ot-aiops protocols) for the live map.


Per-protocol reference

OPC-UA

  • Versions/variants: binary opc.tcp:// via asyncua (sync facade). Security: anonymous + username/password. Certificate message security (Sign / SignAndEncrypt) = roadmap, not validated.
  • Connection params: endpoint_url, username (password encrypted), security_mode, security_policy.
  • Not supported / planned: cert security; real Alarms & Conditions event subscriptions (alarms are surfaced best-effort by browsing alarm-like boolean nodes).

Modbus-TCP

  • Versions/variants: Modbus-TCP via pymodbus. Read function codes FC01 (coils), FC02 (discrete), FC03 (holding), FC04 (input). Write FCs (FC05/06/15/16) = not implemented (read-only preview).
  • Connection params: host, port (502), unit_id. Registers are untyped 16-bit words → decode hint (uint16/int16/uint32/int32/float32/raw); big-endian word order.
  • Coverage: many domestic 国产 PLCs (汇川 Inovance / 信捷 Xinje / 和利时 Hollysys / 台达 Delta) and any Modbus-TCP vendor.

S7comm (Siemens + 仿西门子 国产)

  • Versions/variants: pyS7 (pure-Python, ISO-on-TCP / RFC1006 — no native libsnap7). S7-300/400/1200/1500 and compatible clones. Memory areas DB / M (merker) / I / Q. No protocol auth (CPU gates via "Permit access with PUT/GET").
  • Connection params: host, port (102), rack, slot (0/1 for 1200/1500; 0/2 common for 300/400).
  • Write: s7_write_db = high risk_tier, MOC, dry-run default, captures BEFORE value + undo.
  • Not supported / planned: optimized/symbolic DB access on 1500 with "optimized block access" can require absolute-addressing config on the CPU.

Mitsubishi MC

  • Versions/variants: pymcprotocolMC 3E frame (binary) only. 1E / 4E frames = not supported. PLC types Q / L / QnA / iQ-R / iQ-L. Devices: D/W/R (word), M/X/Y/B (bit).
  • Connection params: host, port (5007 default; set to the module's open MC port), plctype.
  • Write: mc_write_words = high/MOC/dry-run default, captures BEFORE + undo.

MTConnect (ALL CNC machine tools)

  • Versions/variants: agent REST + XML (requests + xml.etree), namespace-agnostic (parses MTConnect 1.x Devices/Streams/Assets schemas). Endpoints: /probe, /current, /sample, /assets. Read-only by specification. XML parsing is hardened (DTD/entity declarations rejected — XXE/billion-laughs defense).
  • Connection params: agent_url (e.g. http://host:5000).
  • Not supported / planned: MTConnect streaming (long-poll interval=); only bounded count= samples.

MQTT / Sparkplug B / UNS

  • Versions/variants: paho-mqttMQTT 3.1.1 & 5. Sparkplug B topic convention spBv1.0/{group}/{type}/{edge}/[device] (NBIRTH/DBIRTH/NDATA/DDATA…). Sparkplug protobuf payloads decode when an optional decoder (tahu) is installed, else reported as binary with a hex preview + hint (JSON/text payloads always decode). TLS + username/password supported.
  • Connection params: host/broker, port (1883 / 8883 TLS), topic, use_tls, username (password encrypted).
  • Command: mqtt_publish = high/MOC/dry-run default; a published command has no automatic inverse.

EtherNet/IP (Rockwell / Allen-Bradley) — roadmap stub

  • ethernetip_status returns a clear "not implemented" + roadmap. Planned lib: pycomm3 (pure-Python Logix tags). Not bundled to keep the install light.

EtherCAT — roadmap stub

  • ethercat_status returns a clear "not implemented" + roadmap. Needs a master stack (pysoem/SOEM) + a dedicated NIC + slave devices.

Install

uv tool install ot-aiops      # or: pip install ot-aiops
ot-aiops init                 # interactive: add endpoints, store passwords encrypted
ot-aiops doctor               # config + per-protocol connectivity probe (point at simulators)
ot-aiops protocols            # the capability map

Master password

Secrets (per-endpoint passwords, MQTT credentials) are never stored in plaintext — they live in ~/.ot-aiops/secrets.enc (Fernet + scrypt). Export OT_AIOPS_MASTER_PASSWORD so the MCP server/CLI can unlock non-interactively:

export OT_AIOPS_MASTER_PASSWORD='…'

Example ~/.ot-aiops/config.yaml (one block per protocol)

endpoints:
  - name: line1
    protocol: opcua
    endpoint_url: opc.tcp://plc.lan:4840
    # username: operator           # password stored encrypted via init/secret set
    tags:
      - { ref: "ns=2;i=5", label: temp, warn_high: 70, alarm_high: 90 }
  - name: plc2
    protocol: modbus
    host: 10.0.0.5
    port: 502
    unit_id: 1
  - name: press1
    protocol: s7
    host: 10.0.0.6
    rack: 0
    slot: 1                        # S7-1200/1500
  - name: cell3
    protocol: mc
    host: 10.0.0.7
    port: 5007
    plctype: iQ-R
  - name: vmc1
    protocol: mtconnect
    agent_url: http://10.0.0.8:5000
  - name: uns
    protocol: mqtt
    host: broker.lan
    use_tls: true                  # → port 8883
    topic: spBv1.0/#
    # username: edge1              # password stored encrypted

ot-aiops init walkthrough (per protocol)

$ ot-aiops init
Step 1 — master password: ********
Step 2 — add an endpoint
  Endpoint name (e.g. line1): press1
  Protocol ('opcua','modbus','s7','mc','mtconnect','mqtt') [opcua]: s7
  S7 PLC host (IP/FQDN): 10.0.0.6
  Port [102]: 102
  Rack (0 for S7-1200/1500) [0]: 0
  Slot (1 for S7-1200/1500, 2 for S7-300/400) [1]: 1
✓ Saved endpoint 'press1'.

(MQTT prompts add TLS/topic/username; MTConnect prompts for agent_url; OPC-UA/MQTT prompt for a hidden password stored encrypted.)

Test against a simulator (per protocol)

  • OPC-UA — an asyncua demo server (the test suite runs a real in-process one).
  • Modbus — ModbusPal or a pymodbus server simulator.
  • S7 — a pyS7/snap7 S7 server sim (Snap7 server) on :102.
  • MTConnect — the public MTConnect demo agent, or a local agent.
  • MQTT — a local mosquitto broker (+ a Sparkplug edge for SpB topics).
  • Mitsubishi MC — GX Simulator / an MC 3E server sim.

Usage

CLI (read)

ot-aiops opcua read "ns=2;i=5" -e line1
ot-aiops modbus holding 0 -e plc2 --count 4 --decode float32
ot-aiops s7 read-db 1 REAL 4 -e press1 --count 2
ot-aiops mc words D100 -e cell3 --count 8
ot-aiops mtconnect oee -e vmc1
ot-aiops mqtt nodes -e uns --timeout-s 15
ot-aiops diag dataflow -e line1 --ref "ns=2;i=5" --freshness-s 30

CLI (write — dry-run by default, double-confirm on --apply)

ot-aiops s7 write-db 1 INT 0 42 -e press1            # dry-run preview
ot-aiops s7 write-db 1 INT 0 42 -e press1 --apply    # double-confirm prompt
ot-aiops mqtt publish factory/line1/cmd '{"setpoint":50}' -e uns --apply

MCP tool calls (JSON args → sample structured return)

s7_read_db:

{ "db": 1, "dtype": "REAL", "start": 4, "endpoint": "press1", "count": 2 }
{ "endpoint": "press1", "area": "DB", "db": 1, "dtype": "REAL", "start": 4,
  "count": 2, "items": [ {"address": "DB1,REAL4", "value": 20.5},
                         {"address": "DB1,REAL8", "value": 4.2} ] }

s7_write_db (dry-run):

{ "db": 1, "dtype": "INT", "start": 0, "value": 42, "endpoint": "press1" }
{ "address": "DB1,INT0", "dry_run": true, "before": 7, "would_write": 42,
  "note": "Dry run — nothing written. Re-run with dry_run=false AND a recorded approver…" }

mtconnect_oee_snapshot:

{ "availability": "AVAILABLE", "execution": "ACTIVE", "controller_mode": "AUTOMATIC",
  "program": "O1234", "available": true, "running": true, "verdict": "running" }

Diagnostics (multi-dimensional JSON for an agent to visualize)

diagnose_dataflow(endpoint="line1", ref="ns=2;i=5", freshness_threshold_s=30):

{ "verdict": "comms_ok_value_stale",
  "diagnosis": "Connected with good status, but the value is STALE (age 412s > 30s) — the source/field upstream has stopped updating this point.",
  "recommended_action": "Trace upstream: the device serves the last value fine, so suspect the source/scanner/field signal that should refresh it.",
  "hops": [ {"hop":"connect","protocol":"opcua","ok":true,"detail":"OPC-UA state=0"},
            {"hop":"read_tag","ref":"ns=2;i=5","ok":true,"detail":"5.0"},
            {"hop":"freshness","evaluated":true,"stale":true,"age_seconds":412.0} ] }

alarm_bad_actors(events=[…]):

{ "event_count": 55, "window_minutes": 0.82, "alarms_per_hour": 4024.4,
  "isa_18_2": {"ok_max":6,"manageable_max":12,"flood_min":30},
  "flood_verdict": "flood",
  "priority_distribution": {"high":50,"low":5},
  "pareto_sources_for_80pct": ["FIC101"],
  "top_offenders": [ {"source":"FIC101","count":50,"share_pct":90.9,"chattering":true,"standing":false} ],
  "chattering": ["FIC101"], "standing": [] }

tag_health(tags=[…]):

{ "evaluated": 4, "overall": "alarm", "offender_count": 3,
  "offenders": [ {"ref":"hot","latest":99,"flags":["out_of_range_alarm"],"severity":3},
                 {"ref":"flat","latest":5,"flags":["flatline"],"severity":2},
                 {"ref":"bad","latest":null,"flags":["bad_quality"],"severity":3} ] }

MCP server

ot-aiops mcp        # stdio transport; or the `ot-aiops-mcp` entry point

Safety & governance

  • Read-first. 33 of 36 protocol tools are read-only. The 3 write/command tools (s7_write_db, mc_write_words, mqtt_publish) are OT-dangerous: governed at high risk_tier, off by default (dry-run), capture the BEFORE value for undo, require a double-confirm in the CLI, and (via policy) a recorded approver — MOC discipline. 未经授权勿对生产控制系统写入.
  • Do not point this at a production control system without authorization. OT networks are safety-critical; even reads add load. Test against a simulator first.
  • All endpoint-returned text is sanitized (prompt-injection defense); secrets are never returned by any tool; MTConnect XML is parsed with DTD/entity declarations refused.
  • Every tool runs through the vendored governance harness: SQLite audit (~/.ot-aiops/audit.db), token/call budget + runaway breaker, risk-tier gate, undo recording.

Roadmap

  • EtherNet/IP read-first Logix tags via an optional pycomm3 extra.
  • EtherCAT read-only PDO/SDO via an optional pysoem extra.
  • OPC-UA certificate security + real Alarms & Conditions subscriptions.
  • Sparkplug B protobuf decode bundled; MTConnect streaming long-poll.

Missing a protocol, device, or feature? 缺功能提 issue/PR 欢迎留言 — open a GitHub issue or PR.

License

MIT © wei

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ot_aiops-0.1.1.tar.gz (105.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ot_aiops-0.1.1-py3-none-any.whl (117.0 kB view details)

Uploaded Python 3

File details

Details for the file ot_aiops-0.1.1.tar.gz.

File metadata

  • Download URL: ot_aiops-0.1.1.tar.gz
  • Upload date:
  • Size: 105.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.0 {"installer":{"name":"uv","version":"0.10.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for ot_aiops-0.1.1.tar.gz
Algorithm Hash digest
SHA256 2cbb7012a031660fdb03a3d77e2804329b849ecf2e2c43db69b743ab0e3a6ef3
MD5 791e55a6c285a9a91beb38793ad3e72f
BLAKE2b-256 9f984b16aff0ec0d29f02cc8db59bca659e95ad7be08d88ea578529d4091aab1

See more details on using hashes here.

File details

Details for the file ot_aiops-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: ot_aiops-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 117.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.0 {"installer":{"name":"uv","version":"0.10.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for ot_aiops-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 511dbc63dce6bad4952f658621368864344afa56b5da24bf8321aa7b740f1312
MD5 be1d21e5996b9be59224f45429456a51
BLAKE2b-256 525ed9fb335c5e647a62f74307119bf98d653607cec0b9192a77631962ac7a25

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page