TTokenySpace
返回 MCP 列表

OT AIops

数据库

Governed OT tap (57 tools): OPC-UA/Modbus/S7/MC/MTConnect/MQTT/EtherNet-IP/EtherCAT.

0Pythonv0.3.0更新于 2026/8/1
GitHub
0

介绍

Governed OT tap (57 tools): OPC-UA/Modbus/S7/MC/MTConnect/MQTT/EtherNet-IP/EtherCAT.

README

<!-- mcp-name: io.github.industrial-aiops/iaiops -->

Industrial-AIOps

English · 中文

Governed, vendor-neutral industrial data tap + intelligent troubleshooting for AI agents — read-first tools across 14 field protocols in this package (17 line-wide with the energy edition): OPC-UA (incl. Historical Access + tag auto-discovery), Modbus-TCP/RTU (byte-order auto-detect + vendor templates), S7comm, Mitsubishi MC, Omron FINS (stdlib-only client), MTConnect, MQTT/Sparkplug B (full decode), EtherNet/IP (Rockwell/Allen-Bradley Logix), EtherCAT (pysoem/SOEM), PROFINET (DCP), SECS/GEM (HSMS fab), HART-IP (process instrumentation), BACnet/IP (building), and IO-Link (master JSON integration), plus two vendor-REST read-only layers above the field bus — a BAS supervisory-controller layer (Johnson Controls Metasys / Tridium Niagara, sitting above the BACnet field connector, building edition) and an Ignition Gateway MES/SCADA read layer (Inductive Automation Ignition's HTTP/Gateway web API — module health, tag browse/read, alarms, tag-history — factory edition) — plus an AI downtime root-cause copilot (with a downtime_triage composer), conservative baseline learning, ISA-18.2 alarm-flood analysis, historian READ integration (RCA pre-incident evidence), a legacy PLC program explainer (ST/AWL/L5X), nine per-industry editions (fab / factory / process / building / water / warehouse / clinical / renewables / plcnext) each carrying its own read-only advisory checks (SPC, PID control-loop, AHU economizer, line bottleneck, medical-gas, disinfection-CT …), open-format export (iaiops export CSV/SQLite/Parquet) with a Prometheus/Grafana bridge, data-quality watchdog, UNS governance, OEE/downtime, asset-inventory, and 信创 (TDengine/IoTDB historian sinks + 防护指南/等保2.0/IEC 62443 compliance mapping, report & evidence bundle). The energy edition (变电/电力: IEC-104 / DNP3 / IEC-61850) ships separately as iaiops-energy.

Industrial-AIOps is the OT member of the industrial-aiops org. 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), scores data trustworthiness, ranks unhealthy tags, computes OEE / categorizes downtime, builds an active asset register, auto-discovers OPC-UA tags into a semantic asset model, and — the flagship — runs an AI downtime root-cause copilot that correlates the evidence into an evidence-cited, advisory verdict. 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).

v0.18.0 — validation status (honest). Grouped by how strongly each path is verified, because "tested" spans a real container round-trip and a synthetic fixture and the difference is what an evaluator needs. Every 待核实 below is hardware-gated, not forgotten — see issue #28.

Verified against real libraries / containers / in-process servers. Pure analysis and the OPC-UA path run against a real in-process asyncua server — including certificate message security (a Sign / SignAndEncrypt matrix) and Alarms & Conditions. IoTDB and TDengine do a live container write→read round-trip. The HART command codec is checked against hart-protocol. Modbus-RTU round-trips over a real serial link (a socat PTY pair + a pymodbus RTU server, tests/test_modbus_rtu_live.py), exercising actual RTU framing. The BACnet/IP read path does a genuine Who-Is discover + present-value read against a real bacpypes3 virtual device on a two-IP subnet in a Linux container (tests/test_bacnet_live.py), through the real async BAC0 (2024+) stack. Phoenix Contact PLCnext vPLC is route-verified over an in-process asyncua server reproducing the Arp.Plc.Eclr GDS address space plus a Modbus-TCP process-data block (tests/test_plcnext_route.py).

Mock-verified — the protocol logic is exercised, no real device is. Omron FINS (in-repo mock UDP/TCP responder, tests/test_fins.py), IO-Link (in-process mock master, both JSON dialects, tests/test_iolink.py), the BAS controller layer (mock supervisory controller in both vendor dialects — Metasys OpenBlue REST and Niagara oBIX/REST), the Ignition Gateway read layer (mock Gateway, both webdev / gateway flavors), EtherNet/IP PCCC for PLC-5 / SLC-500 / MicroLogix / Micro800 (mocked pycomm3 SLCDriver), CC-Link / CC-Link IE Field via master-PLC SLMP, MTConnect long-poll streaming (synthetic advancing / caught-up / reset agents; static XML fixtures elsewhere), Sparkplug B incl. DataSet/Template decode (synthetic Tahu-schema protobuf payloads), and mocked clients for S7 / MC / EtherNet-IP / SECS-GEM.

Pure software, fully covered by the suite. The IAIOPS_NO_EGRESS posture gate and the return envelope (0.17.0–0.18.0).

Still 待核实 — preview, not hardware-verified. Live Omron PLCs (incl. banked-EM access); live IO-Link master datapoint paths; BACnet write / COV / trend on live HVAC; HART-IP wire transport against a live gateway; EtherCAT (no software simulator exists — Linux + root + a real bus only); physical Modbus-RTU RS-485 devices; live PLCnext hardware; a live CC-Link master; real PLC-5 / SLC-500 / MicroLogix / Micro800; a real MTConnect agent's long-poll behaviour; a live MQTT broker for Sparkplug; third-party / vendor OPC-UA servers, certificate-trust enforcement and X509 user tokens; third-party A&C servers; live Metasys / Niagara controllers (incl. native oBIX-XML encoding) and live Ignition gateways (exact API version / paths).

(The energy edition's IEC-104 / DNP3 / IEC-61850 validation lives in the iaiops-energy repo.) See Safety.

Why

OT is exactly where you want an agent on a tight leash: read first, never blind-write. Industrial-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.

🧪 测试与共创 / Beta testing & co-creation

我们在找现场测试伙伴。 软件里能验证的我们都验证了(真实 in-process 服务器、真实协议库、Docker 容器 loopback)——剩下的 待核实 清单只有真设备能回答:物理 Modbus-RTU(RS-485)、EtherCAT 从站、HART 网关、在线 BACnet 楼宇设备、在线 Metasys/Niagara BAS 控制器、在线 Ignition 网关、国产 PLC(汇川/信捷)、真机 PLCnext、真实变电站 RTU/IED、欧姆龙 FINS 真机、IO-Link 主站。如果你是 OT 工程师、系统集成商或工厂团队,手上有任何这类设备:装上 iaiops,对你的设备跑一遍 iaiops doctor,把结果告诉我们。经你验证的设备会署名写进支持矩阵;现场反馈的问题我们优先分诊;功能可以通过 GitHub Issues/Discussions 直接共创。

We're looking for field-testing partners. Everything software-verifiable has been verified; what's left on the honest 待核实 list only real equipment can answer — physical Modbus-RTU (RS-485), EtherCAT slaves, HART gateways, live BACnet HVAC, live Metasys/Niagara BAS controllers, live Ignition gateway, domestic PLCs (Inovance/Xinje), live PLCnext, substation RTUs/IEDs, live Omron FINS PLCs, IO-Link masters. If you're an OT engineer, integrator, or factory team with access to any of these: install iaiops, run iaiops doctor against your gear, and tell us what happened. Verified-equipment reports get credited in the support matrix, field-reported issues get fast triage, and features are co-designed in the open via GitHub Issues/Discussions.

👉 参与入口 | Start here: #28 — 招募现场测试伙伴 | Call for field-testing partners (v0.10.0) (pinned)


Consolidated capability matrix

ProtocolToolOperationR/Wrisk_tierReturns (key fields)
OPC-UAopcua_server_infoserver statusRlowstate, product_name, namespaces
OPC-UAopcua_browsebrowse node treeRlow[{node_id, browse_name, depth}]
OPC-UAopcua_read_noderead one nodeRlowvalue, datatype, source_timestamp, good
OPC-UAopcua_read_manybatch readRlow[{node_id, value, ...}]
OPC-UAopcua_subscribe_samplebounded sampleRlow{collected, samples[]}
OPC-UAopcua_read_alarmsalarm surfacingRlow{active_alarms[], active_count}
OPC-UAopcua_read_historyHistorical Access (HDA)Rlow{supported, count, values[]}
OPC-UAopcua_diagnose_connectionconnection triageRlow{verdict, checks[]}
OPC-UAopcua_discover_tagstag auto-discovery → semantic asset modelRlow{tag_count, assets[], naming_report}
OPC-UAopcua_health_summarythreshold classify (was health_summary¹)Rlow{overall, counts, offenders[]}
OPC-UAopcua_anomaly_scanstddev outliers (was anomaly_scan¹)Rlow{mean, stddev, outliers[]}
Modbusmodbus_read_holdingFC03Rlow{raw_registers, decoded[]}
Modbusmodbus_read_inputFC04Rlow{raw_registers, decoded[]}
Modbusmodbus_read_coilsFC01Rlow{bits[]}
Modbusmodbus_read_discreteFC02Rlow{bits[]}
Modbusmodbus_detect_byte_orderbyte/word-order auto-detectRlow{best_order, candidates[]}
Modbusmodbus_list_templatesvendor register templatesRlow{templates[]}
Modbusmodbus_apply_templatedecode block via templateRlow{values:{name: engineering_value}}
Modbusmodbus_health_summarythreshold classifyRlow{overall, counts, offenders[]}
S7comms7_cpu_infoCPU id + run/stopRlow{cpu_status, cpu_info}
S7comms7_read_arearead DB/M/I/QRlow{items:[{address, value}]}
S7comms7_read_dbread data blockRlow{items:[{address, value}]}
S7comms7_read_manybatch addressesRlow{items:[{address, value}]}
S7comms7_write_dbwrite data blockWhigh/MOC{before, written, _undo_id}
Mitsubishi MCmc_cpu_statusCPU typeRlow{cpu_type, cpu_code}
Mitsubishi MCmc_read_wordsword devicesRlow{words[]}
Mitsubishi MCmc_read_bitsbit devicesRlow{bits[]}
Mitsubishi MCmc_read_manyrandom readRlow{words[], dwords[]}
Mitsubishi MCmc_write_wordswrite wordsWhigh/MOC{before, written, _undo_id}
Omron FINSfins_cpu_infocontroller data read (0501)Rlow{controller_model, controller_version}
Omron FINSfins_cpu_statuscontroller status (0601)Rlow{run_mode, status}
Omron FINSfins_read_wordsmemory-area word read (DM/CIO/W/H/A/EM)Rlow{words[]}
Omron FINSfins_read_bitsmemory-area bit readRlow{bits[]}
Omron FINSfins_read_manybatch readsRlow{items[]}
Omron FINSfins_write_wordsmemory-area writeWhigh/MOC{before, written, _undo_id}
MTConnectmtconnect_probedevice modelRlow{devices:[{components:[{data_items}]}]}
MTConnectmtconnect_currentlatest valuesRlow{observations[]}
MTConnectmtconnect_samplebounded streamRlow{observations[]}
MTConnectmtconnect_assetsassetsRlow{assets[]}
MTConnectmtconnect_oee_snapshotOEE inputsRlow{availability, execution, verdict}
MQTT/Sparkplugmqtt_read_topicbounded readRlow{messages:[{topic, payload}]}
MQTT/Sparkplugsparkplug_subscribe_samplebounded SpB sample (full decode)Rlow{samples:[{sparkplug, payload:{metrics[]}}], seq_gap_count}
MQTT/Sparkplugsparkplug_decode_payloaddecode raw SpB payloadRlow{metrics:[{name, alias, datatype, value, is_historical}]}
MQTT/Sparkplugsparkplug_node_listnode discovery + stateRlow{nodes:[{group_id, edge_node_id, online, devices}], primary_hosts[]}
MQTT/Sparkpluguns_browsetopic-tree browseRlow{topics[], tree{}}
MQTT/Sparkpluguns_topic_auditUNS naming + sprawl governanceRlow{verdict, sprawl_findings, findings{casing_collisions[], scattered_leaves[], …}}
MQTT/Sparkpluguns_schema_driftSparkplug schema-drift (baseline vs current)Rlow{verdict (none/additive/breaking), node_changes[]}
MQTT/Sparkpluguns_live_auditlive UNS audit (bounded broker sample)Rlow{verdict, findings{}}
MQTT/Sparkplugsparkplug_live_schemalive NBIRTH schema snapshotRlow{nodes[], metrics[]}
MQTT/Sparkpluguns_live_driftlive drift vs stored baselineRlow{verdict, node_changes[]}
MQTT/Sparkplugmqtt_publishpublish/commandWhigh/MOC{published_bytes, applied}
EtherNet/IPeip_controller_infoLogix controller idRlow{controller:{vendor, product_name, revision, serial}}
EtherNet/IPeip_list_tagstag discoveryRlow{tag_count, tags:[{name, data_type, structure}]}
EtherNet/IPeip_read_tagread one tag/arrayRlow{tag, value, type, good}
EtherNet/IPeip_read_manybatch readRlow{items:[{tag, value, type}]}
EtherNet/IPeip_write_tagwrite tagWhigh/MOC{before, written, _undo_id}
Diagnosticsdiagnose_dataflowlocalize no-dataRlow{verdict, diagnosis, hops[]}
Diagnosticsalarm_bad_actorsISA-18.2 floodRlow{flood_verdict, top_offenders[]}
Diagnosticstag_healthoffender rankingRlow{overall, offenders[]}
Diagnosticshistorian_healthgap/flatlineRlow{verdict, gaps[]}
Diagnosticssubscription_healthsequenced-feed loss/reorder/overloadRlow{verdict, missed_count, overloaded_channels[]}
Diagnosticsdowntime_root_causeAI downtime RCA copilot (cited, advisory)Rlow{verdict, primary_cause, hypotheses:[{cause, confidence, evidence[]}]}
Diagnosticsdowntime_root_cause_liveRCA copilot that gathers its own live evidenceRlow{…downtime_root_cause…, collected_evidence}
Diagnosticslearn_cause_weightslearn per-site RCA cause weights from labeled incidentsRlow{cause_weights{}, rationale}
Diagnosticsdata_quality_scorecardfleet data-trust rollupRlow{fleet_score, fleet_status, issue_breakdown, worst_tags[], endpoints[]}
Diagnosticsdata_quality_fleet_rollupcross-endpoint fleet viewRlow{fleet_score, endpoints[]}
Diagnosticsheartbeat_healthheartbeat/watchdog livenessRlow{alive, distinct_transitions, longest_stall_s, reason}
Alarm (ISA-18.2)alarm_flood_analysisflood episodes / chattering / stale / summaryRlow{episodes[], chattering[], stale[], summary{}}
Alarm (ISA-18.2)alarm_rationalization_worksheetCSV-exportable rationalization rowsRlow{rows[], csv_path?}
Baselinebaseline_learnconservative change-log baseline (refuses thin history)Rlow{band{p1,p99,median,mad} | insufficient_data}
Baselinebaseline_checksilent-by-default violation checkRlow{status, violations[] (cited)}
Baselinebaseline_record_changerecord operator change (restarts learning)Rlow{recorded, change_point}
Baselinebaseline_statusno_baseline / learning / ok / violationRlow{status, window}
Historianhistorian_queryread history back out of sqlite/TDengine/IoTDBRlow{rows[], truncated}
Historianhistorian_coverageper-tag row counts + first/last tsRlow{tags:[{tag, rows, first, last}]}
PLC programplc_program_outlinestructure of exported ST/AWL/L5X programRlow{blocks[], call_graph, timers[]}
PLC programplc_program_xrefsymbol/address cross-reference (cited lines)Rlow{sites:[{kind, source_file, line, quote}]}
PLC programplc_program_sectionone named block's source (≤200 lines)Rlow{text, source_file}
Exportexport_dataexport local store → CSV/SQLite/ParquetRlow{path, row_count, preview[]}
Analyticsoee_computeOEE = A×P×QRlow{availability, performance, quality, oee, oee_pct}
Analyticsdowntime_eventsstoppage detect + categorizeRlow{event_count, total_downtime_s, by_category, events[]}
Analyticsoee_multidimOEE machine×part×shiftRlow{matrix[], worst_performers[], mean_oee}
Analyticsasset_inventoryactive fingerprintRlow{assets:[{protocol, vendor, model, firmware, reachable}]}
Analyticscross_protocol_asset_modelmerge discovered tags into one asset modelRlow{assets[], tag_count}
Analyticsadopt_alias_map / diff_alias_maptag alias-map adopt/diffRlow{aliases{}, changes[]}
Analyticsmonitor_changesbounded change-of-valueRlow{change_count, changes:[{value, previous, wall_clock}]}
EtherCATethercat_master_statemaster/WKC + slave countRlow{master_state, expected_working_counter, slaves_found, slaves_expected}
EtherCATethercat_slavesbus scanRlow{slave_count, slaves:[{index, name, vendor_id, product_code, state}]}
EtherCATethercat_slave_infoslave detailRlow{sync_managers[], fmmus[], object_dictionary[], input_bytes}
EtherCATethercat_read_sdoCoE SDO uploadRlow{index, byte_length, hex, as_uint}
EtherCATethercat_read_pdoinput PDO snapshotRlow{working_counter, input_hex, input_byte_length}
EtherCATethercat_write_sdoCoE SDO downloadWhigh/MOC{before, written, applied}
EtherCATethercat_set_stateAL-state transitionWhigh/MOC{before, requested, reached, applied}
PROFINETprofinet_discoverDCP IdentifyAll (segment-wide)Rlow{station_count, stations:[{name_of_station, mac, ip, vendor_id, device_roles[]}]}
PROFINETprofinet_identify_stationidentify by name-of-stationRlow{found, name_of_station, mac, ip, device_family}
PROFINETprofinet_station_paramstargeted DCP Get (by MAC)Rlow{found, name_of_station, ip, netmask, gateway}
PROFINETprofinet_asset_inventoryDCP asset registerRlow{asset_count, io_controller_count, assets[]}
PROFINETprofinet_dcp_setDCP Set (station name / IP suite)Whigh/MOC{before, applied, _undo_id}
SECS/GEMsecsgem_equipment_statusGEM link + identity (S1F1/F2)Rlow{communication_state, are_you_there}
SECS/GEMsecsgem_list_status_variablesSVID namelist (S1F11/F12)Rlow{count, status_variables[]}
SECS/GEMsecsgem_read_status_variablesSVID values (S1F3/F4)Rlow{svids, values[]}
SECS/GEMsecsgem_list_equipment_constantsECID namelist (S2F29/F30)Rlow{count, equipment_constants[]}
SECS/GEMsecsgem_read_equipment_constantsECID values (S2F13/F14)Rlow{ecids, values[]}
SECS/GEMsecsgem_list_alarmsalarm list (S5F5/F6)Rlow{count, alarms[]}
SECS/GEMsecsgem_list_process_programsPPID directory (S7F19/F20)Rlow{count, process_programs[]}
BACnet (building)bacnet_discoverWho-Is device discoveryRlow{device_count, devices:[{device_id, address}]}
BACnet (building)bacnet_object_lista device's objectsRlow{object_count, objects:[{object_type, instance}]}
BACnet (building)bacnet_read_propertyone object propertyRlow{object_type, instance, property, value}
BACnet (building)bacnet_read_pointsall present-values (HVAC snapshot)Rlow{point_count, points:[{object_type, instance, present_value}]}
BACnet (building)bacnet_cov_subscribebounded COV capture (always unsubscribes)Rlow{notifications[], terminated_reason}
BACnet (building)bacnet_read_trend_logTrendLog readRange (bounded)Rlow{records:[{timestamp, value}]}
BACnet (building)bacnet_write_propertypresent-value write (priority)Whigh/MOC{before, written, _undo_id}
HART-IP (process)hart_device_identitycmd 0 identityRlow{manufacturer, device_type, revision}
HART-IP (process)hart_primary_variablecmd 1 PVRlow{value, unit}
HART-IP (process)hart_dynamic_variablescmd 3 PV/SV/TV/QV + loop currentRlow{variables[], loop_current}
HART-IP (process)hart_burst_samplebounded burst-variable samplingRlow{samples[]}
IO-Linkiolink_master_infomaster identityRlow{vendor, product, serial}
IO-Linkiolink_ports≤32-port sweep (mode/status/device id)Rlow{ports[]}
IO-Linkiolink_device_infoper-port device identityRlow{vendor_id, device_id, product_name}
IO-Linkiolink_read_pdinprocess-data-in (raw hex + bytes)Rlow{hex, bytes[]}
IO-Linkiolink_read_isduISDU acyclic parameter readRlow{index, subindex, value}
IO-Linkiolink_scanmaster + all connected devicesRlow{master{}, devices[]}
BAS (Metasys/Niagara)bas_point_listsupervisory point directoryRlow{point_count, points:[{id, name, type}]}
BAS (Metasys/Niagara)bas_point_readread one supervisory pointRlow{point, value, unit, status}
BAS (Metasys/Niagara)bas_alarm_listactive controller alarmsRlow{alarm_count, alarms:[{id, priority, state}]}
BAS (Metasys/Niagara)bas_trend_readtrend/history samples (bounded)Rlow{records:[{timestamp, value}]}
BAS (Metasys/Niagara)bas_commandsupervisory command (default-OFF; life-safety object denylist refuses fire/smoke/egress/pressurization before any I/O)Whigh/MOC{before, written, _undo_id}
Ignitionignition_gateway_statusGateway + module healthRlow{state, version, modules:[{name, state}]}
Ignitionignition_tag_browsetag-tree browseRlow{tags[], tree{}}
Ignitionignition_tag_readcurrent tag valuesRlow{values:[{path, value, quality, timestamp}]}
Ignitionignition_alarm_statusactive alarmsRlow{alarm_count, alarms:[{path, priority, state}]}
Ignitionignition_tag_historytag-history query (bounded)Rlow{rows:[{path, timestamp, value}]}
信创 / compliancecompliance_mapping《工控网络安全防护指南》↔ iaiopsRlow{pillars[], status_summary, controls:[{pillar, status, gap}]}
信创 / compliancecompliance_frameworks等保 2.0 + IEC 62443 FR1–6 crosswalkRlow{controls:[{crosswalk}]}
信创 / compliancecompliance_dengbao_levels等保 二级 baseline vs 三级 增量Rlow{pillars:[{l2, l3_delta, status}]}
信创 / compliancecompliance_reportdeliverable compliance report (md/html)Rlow{markdown | out_path}
信创 / compliancecompliance_evidence_bundleaudit-evidence zip (hash-chain verified)Rlow{bundle_path, manifest}
信创 / historianhistorian_pushpush telemetry to sqlite/TDengine/IoTDBR(→historian)low{sink, received, written, skipped_non_numeric}
Selfprotocols_supportedcapability mapRlow{protocols[], diagnostics[], analytics[]}

(The energy protocols — IEC-104 / DNP3 / IEC-61850 — moved to iaiops-energy in 0.8.0; their tool matrix lives in that repo.)

166 governed tools = 156 read + 10 MOC-gated writes (s7_write_db, mc_write_words, fins_write_words, mqtt_publish, eip_write_tag, ethercat_write_sdo, ethercat_set_state, profinet_dcp_set, bacnet_write_property, bas_command). The read side now includes two vendor-REST read-only layers above the field protocols — a BAS controller layer (Metasys/Niagara, building edition) and an Ignition Gateway MES/SCADA layer (factory edition). ¹ The 156 reads include the two deprecated brain aliases health_summary / anomaly_scan, renamed to opcua_health_summary / opcua_anomaly_scan in 0.10.0 — the deprecated aliases are still registered and will be removed in a future release (target: 1.0.0). Read-only per-edition tools load ONLY under their edition (see per-edition tool modules below), so a bare protocol / single-edition surface is smaller than this line-wide total. The table above is representative, not exhaustive; run protocols_supported() (or iaiops protocols) for the live map.


Per-protocol reference

OPC-UA

  • Versions/variants: binary opc.tcp:// via asyncua (sync facade). Security: anonymous + username/password, plus application-certificate message security (Sign / SignAndEncrypt) — set client_cert + client_key (+ optional server_cert) and the client opens a signed/encrypted secure channel (no cert ⇒ the anonymous / username path is unchanged). Validated end-to-end against an in-process asyncua server (tests/test_opcua_security.py) for Basic256Sha256 in both Sign and SignAndEncrypt modes: server_cert pinning and client-side server-cert auto-discovery are exercised, and the test asserts the negotiated policy URI + message-security mode on the live encrypted channel (plus a negative test that anonymous is refused by a secure-only server).
  • Connection params: endpoint_url, username (password encrypted), security_mode, security_policy; for cert security client_cert / client_key / optional server_cert (PEM or DER paths; aliases certfile / keyfile).
  • Alarms & Conditions: opcua_alarm_events — bounded event subscription + ConditionRefresh, events carry the server's own timestamps (verified against an in-process asyncua server; third-party A&C servers 待核实). Untimed fallback: opcua_read_alarms browses alarm-like boolean nodes.
  • Not supported / planned (待核实): cert-security interop with third-party / vendor servers (KEPServerEX / Prosys / Siemens / real PLCs), the other policies (Aes128Sha256RsaOaep / Aes256Sha256RsaPss / Basic128Rsa15 / Basic256), strict server-side certificate-trust enforcement, and cert-based user identity (X509 identity token, distinct from channel security).

Modbus-TCP / Modbus-RTU

  • Versions/variants: Modbus-TCP and Modbus-RTU (serial RS-485/232) via pymodbus (+ pyserial). Read function codes FC01 (coils), FC02 (discrete), FC03 (holding), FC04 (input). Write FCs (FC05/06/15/16) = not implemented (read-only).
  • Connection params: TCP — host, port (502), unit_id. RTU — transport: rtu, serial_port (e.g. /dev/ttyUSB0), baudrate, unit_id. Registers are untyped 16-bit words → decode hint (uint16/int16/uint32/int32/float32/raw); modbus_detect_byte_order auto-detects the byte/word order (AB/BA · ABCD/DCBA/BADC/CDAB) from hint values — pure logic, no extra device load.
  • Vendor register templates (modbus_list_templates / modbus_apply_template): named register maps decoding a block into engineering values — energy meters (Eastron SDM630, Schneider PM5xxx, Carlo Gavazzi EM24), PV inverters (Huawei SUN2000, Growatt), Phoenix PLCnext process data, and water-industry templates (E+H Promag, Hach SC controller, generic dosing pump). Each template carries an explicit 待核实 caveat — no invented "verified" addresses.
  • Coverage: many domestic 国产 PLCs (汇川 Inovance / 信捷 Xinje / 和利时 Hollysys / 台达 Delta) and any Modbus vendor. RTU framing is live-verified over a real serial link (socat PTY + pymodbus RTU server); specific physical RS-485 devices stay 待核实.

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.

Omron FINS (CS/CJ/CP/NX-via-FINS)

  • Versions/variants: in-repo, stdlib-only FINS client (no third-party dependency — the iaiops[fins] extra pins nothing): 10-byte FINS header framing, FINS/UDP (default port 9600) and FINS/TCP (node-address handshake per Omron W342), SID matching, bounded response parsing, end-code table per W227/W342. Commands: 0101 memory-area read (words/bits over DM/CIO/W/H/A/EM), 0102 write, 0501 controller data read, 0601 controller status.
  • Connection params: host, port (9600), transport (udp default / tcp), FINS network/node/unit addressing.
  • Write: fins_write_words = high/MOC/dry-run default, captures BEFORE + undo; CLI double-confirm on --apply.
  • Validation: verified against an in-repo mock FINS UDP/TCP responder (tests/test_fins.py); live Omron PLC behaviour and banked-EM access stay 待核实.

IO-Link (master JSON integration — read-only)

  • Versions/variants: sensor-level visibility via the IO-Link master's HTTP/JSON interface (IO-Link consortium "JSON Integration"), both dialects selectable per endpoint via flavor:iotcore (ifm IoT-Core POST envelope, default) and rest (plain-REST GET, Balluff/Turck-style). Reads: master identity, bounded ≤32-port sweep, per-port device identity, process-data-in (raw hex + bytes), ISDU acyclic parameter read. NO write tools. Bounded/size-capped HTTP (256 KiB response cap), schema-checked JSON with teaching errors. Reuses the MTConnect HTTP pin (iaiops[iolink]requests).
  • Connection params: master host/URL, flavor, timeout_s. protocol: iolink.
  • Validation: in-process mock master in both flavors (tests/test_iolink.py); live master datapoint paths stay 待核实.

HART-IP (process instrumentation — read-only)

  • Versions/variants: HART universal commands over HART-IP UDP (default, port 5094) or TCP (transport: tcp, length-delimited framing) via an in-tree transport; the HART command codec is verified vs hart-protocol. Tools: hart_device_identity (cmd 0), hart_primary_variable (cmd 1), hart_dynamic_variables (cmd 3, PV/SV/TV/QV + loop current), hart_burst_sample (bounded sampling of burst-published variables). No write / device-specific commands exposed (OT-dangerous on live instruments).
  • Connection params: host (HART-IP server/gateway), port (5094), transport (udp default / tcp).
  • Validation: TCP transport loopback-verified (in-process HART-IP server, real long-frame ACK through the real codec path); live gateway behaviour and a true unsolicited burst subscription stay 待核实.

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/NDEATH/DDEATH/STATE). TLS + username/password supported.
  • Full Sparkplug B decode (no optional extra): payloads are protobuf-decoded with a vendored, byte-for-byte copy of the official Eclipse Tahu sparkplug_b.proto generated module (depends only on protobuf). Per metric you get name, alias (resolved to its name via the BIRTH model), datatype (Int8…Int64/UInt…/Float/Double/Boolean/String/DateTime/Text/UUID/DataSet/Bytes/File/Template/PropertySet…), value, timestamp, and the is_historical / is_null flags. A birth/death + seq model tracks node/device online state (NBIRTH/DBIRTH ↔ NDEATH/DDEATH), builds the alias→name map from BIRTH, applies NDATA/DDATA by alias, and flags seq gaps / out-of-order. Primary-host awareness: STATE/<host_id> topics surface in sparkplug_node_list. sparkplug_decode_payload decodes a single raw payload (base64/hex) offline.
  • Connection params: host/broker, port (1883 / 8883 TLS), topic, use_tls, username (password encrypted).
  • Command: mqtt_publish = high/MOC/dry-run default. A transient publish has no automatic inverse (delivered is delivered); a retained one overwrites durable broker state, so it captures the prior retained payload and records an inverse.

EtherNet/IP (Rockwell / Allen-Bradley)

  • Supported: ControlLogix / CompactLogix (and GuardLogix) via CIP / EtherNet-IP using pycomm3 (pure-Python — no native deps). Tag-based, symbolic access: read/write tags by name (Conveyor.Speed, Array[3], Program:Main.X) and discover the controller's tag list at runtime (eip_list_tags, the headline feature). eip_controller_info reads the controller identity.
  • Connection params: host, slot (0 for CompactLogix; the CPU slot for a ControlLogix chassis), port (44818). protocol: ethernetip (alias eip).
  • Write: eip_write_tag = high risk_tier, MOC, dry-run default, captures BEFORE value + undo.
  • Not supported / planned: PLC-5 / SLC-500 (PCCC) and Micro800 are not supported = roadmap (Logix tag model only).

EtherCAT (pysoem / SOEM fieldbus master)

  • Supported: a real EtherCAT master via pysoem (the Python binding for the SOEM C stack). CoE SDO read (ethercat_read_sdo, acyclic mailbox upload) + SDO write (ethercat_write_sdo, download), input PDO read (ethercat_read_pdo, one bounded cyclic snapshot), bus scan / slave enumeration (ethercat_slaves, ethercat_slave_info — identity, SM/FMMU mapping, object-dictionary summary), master/working-counter state (ethercat_master_state), and AL-state transitions INIT↔PREOP↔SAFEOP↔OP (ethercat_set_state).

  • HARD REQUIREMENTS (no way around them): Linux, root or CAP_NET_RAW, a dedicated NIC cabled to the bus, and real EtherCAT slave hardware. pysoem is an OPTIONAL extra: pip install iaiops[ethercat] — the base package installs and imports without it, and every EtherCAT tool then degrades to a teaching error (never crashes, never imports pysoem at module load).

  • NOT supported: no software simulator exists (unlike OPC-UA / Modbus) — EtherCAT is hardware-only and not testable in mock-only CI; macOS is unsupported. EoE / FoE / SoE mailbox protocols and full PDO-mapping decode/expansion = roadmap.

  • Connection params: nic (the dedicated interface name, e.g. eth1; alias interface), optional expected_slaves (a sanity check vs the bus scan). protocol: ethercat.

  • Operations matrix:

    ToolOpR/WriskCapture/notes
    ethercat_master_statemaster + WKC state, slave countRlowexpected vs found
    ethercat_slavesbus scan / enumerateRlowindex/vendor/product/rev/addr/AL-state
    ethercat_slave_infoone-slave detailRlowSM/FMMU + OD summary
    ethercat_read_sdoCoE SDO uploadRlowhex + uint interpretation
    ethercat_read_pdoinput PDO snapshotRlowsingle cycle, never loops
    ethercat_write_sdoCoE SDO downloadWhigh/MOCbefore-value (SDO read-back) + undo
    ethercat_set_stateAL-state transitionWhigh/MOCbefore-state + undo; can start/stop motion
  • Write/state safety: ethercat_write_sdo (hex little-endian bytes) and ethercat_set_state are high risk_tier, MOC, dry-run by default, capture the BEFORE value/state for undo, and need a CLI double-confirm. Changing EtherCAT state can START or STOP machine motion — treat with extreme care. 未经授权勿对生产控制系统写入.

PROFINET (DCP discovery / identify + gated DCP Set)

  • Supported: layer-2 PROFINET-DCP via pnio-dcpprofinet_discover (DCP IdentifyAll: one broadcast surfaces every station on the segment — name-of-station, MAC, IP, vendor/device id, role — closer to passive discovery than a per-device fingerprint), profinet_identify_station (by name-of-station), profinet_station_params (targeted DCP Get by MAC → name + IP suite), and profinet_asset_inventory (a register with IO-controller vs IO-device role decoding).
  • Write: profinet_dcp_set re-addresses one station (name-of-station and/or IP suite, by MAC) — high risk_tier, MOC, dry-run default, captures the BEFORE addressing + undo descriptor. Re-addressing a live station can disrupt its IO connection.
  • Scope (deliberate): no RT cyclic process data (that needs an IO-controller/IO-device stack and hard real-time — out of scope and unsafe to tap); the blink / factory-reset DCP services stay unexposed.
  • HARD REQUIREMENTS: raw-socket access (root / admin / CAP_NET_RAW) on the NIC on the PROFINET subnet. pnio-dcp is an OPTIONAL extra: pip install iaiops[profinet] — the base package installs/imports without it, and every tool then degrades to a teaching error.
  • Connection params: hostTHIS machine's IP on the PROFINET subnet (the DCP broadcast goes out on it). protocol: profinet.
  • Preview caveat: validated against a mocked pnio-dcp DCPnot verified against live PROFINET devices yet.

Energy edition (electrical substation / utility telecontrol) → iaiops-energy

The energy vertical — IEC 60870-5-104 / DNP3 / IEC 61850 MMS read-only monitoring for substation RTUs/IEDs — moved to its own package in 0.8.0: iaiops-energy (pip install iaiops-energy), built on iaiops.core (shared governance / brain / runtime). Its protocol reference, support matrix, and validation status live in that repo.

Building edition (facility / HVAC / 厂务)

The building vertical adds BACnet/IP (ASHRAE 135) — the dominant building-automation protocol for HVAC, lighting, metering, and facility plant. Install with pip install iaiops[building] and expose with IAIOPS_MCP=building (bundle: bacnet + modbus + opcua + iolink).

  • BACnet/IP (BAC0 over bacpypes3): bacnet_discover (Who-Is device discovery), bacnet_object_list (a device's objects), bacnet_read_property (one object property), bacnet_read_points (present-value of all analog/binary/multistate points — the HVAC snapshot), bacnet_cov_subscribe (bounded change-of-value capture — capped by count AND wall-clock, always unsubscribes), bacnet_read_trend_log (TrendLog buffered records via one bounded readRange). Config: host = THIS machine's BACnet/IP interface (ip or ip/mask) / port (47808).
  • Write: bacnet_write_property (present-value at a BACnet priority 1..16, or relinquish) = high risk_tier, MOC, dry-run default, BEFORE-value read-back + undo. Overriding a live building-control point can move real HVAC/plant.
  • Validation: the read path is verified against a real bacpypes3 virtual BACnet/IP device through the actual async BAC0 stack (tests/test_bacnet_live.py); COV / trend-log / writes on live HVAC gear stay 待核实.

Water treatment edition (水处理)

IAIOPS_MCP=water (or iaiops-mcp-water, pip install iaiops[water]) exposes modbus + opcua + hart + the brain — the protocol set waterworks / wastewater plants actually run. Adds water-domain tag semantics (溶解氧 DO / ORP / 余氯 chlorine / 氨氮 ammonia / TSS/MLSS / 跨膜压差 TMP / UV / 加药 dosing / 曝气 aeration) and water-industry Modbus templates (E+H Promag, Hach SC controller, generic dosing pump — all with explicit 待核实 caveats).

Warehouse / intralogistics edition (仓储 / 物料搬运)

IAIOPS_MCP=warehouse (or iaiops-mcp-warehouse, pip install iaiops[warehouse]) exposes eip + profinet + modbus + opcua + sparkplug + the brain — conveyor & sorter drives over EtherNet/IP (Rockwell) and Profinet (Siemens), VFD / energy meters over Modbus (conveyor_vfd / agv_battery templates), WMS/WCS gateways over OPC-UA, and AMR/IoT telemetry over MQTT-Sparkplug. Edition tools (read-only, advisory): line_bottleneck (Theory-of-Constraints throughput bottleneck across stations) + sortation_health. PdM (pdm_forecast), downtime_triage and OEE are reused as-is.

Clinical-facility edition (医疗设施)

IAIOPS_MCP=clinical (or iaiops-mcp-clinical, pip install iaiops[clinical]) exposes bacnet + modbus + opcua + the brain — hospital facilities as a distinct patient-safety vertical over the building brain. Edition tools (read-only, advisory): isolation_room_check (负压/正压 isolation-room pressurization), medical_gas_check (medical-gas alarm-panel safety), or_environment_check (OR temperature / humidity / pressure envelope). BACnet BMS + Modbus gas-alarm panels + OPC-UA plant SCADA.

Renewables edition (光伏 / 风电)

IAIOPS_MCP=renewables (or iaiops-mcp-renewables, pip install iaiops[renewables]) exposes modbus + opcua + sparkplug + the brain — PV inverters (SUN2000 / Growatt templates) + wind-turbine controllers over Modbus, OPC-UA plant SCADA, and MQTT-Sparkplug telemetry. Edition tool (read-only, advisory): pv_performance (PV string performance vs expectation). Device-level monitoring + PdM via baseline / RCA.

PLCnext packaging edition (Phoenix Contact vPLC)

IAIOPS_MCP=plcnext (or iaiops-mcp-plcnext, pip install iaiops[plcnext]) exposes opcua + modbus + the brain — the Phoenix Contact PLCnext virtualized PLC reached over its built-in OPC-UA server (opc.tcp 4840, Arp.Plc.Eclr address space) + Modbus-TCP process-data server; no new connector. Route-verified in-process; live PLCnext hardware reads stay 待核实 (see validation status above).

信创 / China entry (offline · 国产 TSDB · compliance)

For 自主可控 / 信创 deployments — see docs/CHINA.md for the full guide.

  • Air-gapped install: pure-Python core + per-protocol optional extras → install from a local wheelhouse with pip install --no-index --find-links ./wheelhouse "iaiops[...]"; secrets stay local (encrypted store), no cloud KMS.
  • National TSDB historian sink (historian_push, CLI iaiops historian push): write collected telemetry to TDengine (iaiops[tdengine]) or Apache IoTDB (iaiops[iotdb]) — domestic, controllable; we don't build our own store or bind InfluxDB. Data egress to the operator's own historian, not a control write.
  • Compliance mapping (compliance_mapping, CLI iaiops compliance): an honest 《工控系统网络安全防护指南》 ↔ iaiops self-assessment across 分区隔离 / 可审计 / 双向认证 / 最小权限 / 数据保护 / 自主可控, with per-control status (addressed / partial / 待核实) and the named gap.
  • 国产 PLC: 汇川 / 台达 / 信捷 over the existing Modbus-TCP / S7 connectors.
  • ⚠️ 待核实: 国产 OS (麒麟/统信) · 芯 (鲲鹏/海光) · PLC validation and the TSDB write paths are documented but not yet hardware-verified — see the validation matrix in docs/CHINA.md.

OEE / downtime analytics (cross-protocol, read-only)

  • oee_computeOEE = Availability × Performance × Quality from production inputs (planned time, run time, ideal cycle, total/good counts). Each factor is reported raw + clamped to [0,1]; a capped performance >1.0 flags an optimistic ideal cycle.
  • downtime_events — auto-detects running→stopped transitions in a {timestamp, state} series and produces stoppage events with durations, categorized (changeover / material / mechanical / quality / break / unknown, by keyword heuristics or a {state: category} override).
  • oee_multidim — aggregates OEE across machine × part × shift (or any dimensions) from labelled records → the matrix + worst performers.
  • Operate over provided/collected inputs (fully testable without a plant). mtconnect_oee_snapshot surfaces the live MTConnect availability/execution inputs that feed these.

Active asset inventory / fingerprint (read-only)

  • asset_inventory — for each configured (or named) endpoint, actively connects with our own protocol client and reads its identity call (S7 s7_cpu_info, EtherNet/IP eip_controller_info, OPC-UA server build info, Modbus Device Identification FC43/0x2B, Mitsubishi CPU type, MTConnect device model), aggregating vendor / model / firmware / serial / reachable / last_seen into an asset register.
  • Honest scope (IEC 62443-flavored): this is ACTIVE fingerprinting via our client connections, NOT passive SPAN/tap discovery — it only finds devices we are configured to reach and adds light load to each. Passive, traffic-mirroring discovery is roadmap.

OPC-UA Historical Access (HDA)

  • opcua_read_history — reads stored historical values for a node over a [start,end] ISO-8601 window via the server's HistoryRead service (asyncua read_raw_history), bounded by max_points (≤2000). Returns {supported:false, note} gracefully when the server does not historize the node (no crash). Read-only.

Change-of-value (CoV) monitor

  • monitor_changes — bounded deadband report: polls a point and returns only the value CHANGES (with timestamps), not every sample. Works over OPC-UA / Modbus / S7 / Mitsubishi MC / EtherNet-IP. Never an infinite loop — hard-capped by both duration_s (≤120) and max_changes (≤500). Read-only.

Cross-protocol brain — 0.9/0.10 additions (all read-only)

  • Conservative baseline learning (baseline_learn/check/record_change/status, CLI iaiops baseline …) — a change-log baseline, explicitly NOT black-box anomaly detection: robust p1/p99 + median/MAD band over the local history, refuses thin history (<100 samples or <24h) with an explicit insufficient_data verdict, restarts at recorded operator changes, and is silent by default — a violation needs >3×MAD beyond the band AND ≥3 consecutive samples, and every violation cites its baseline window and offending samples.
  • Historian READ integration (historian_query / historian_coverage, CLI iaiops historian query|coverage) — query history back out of the sqlite/TDengine/IoTDB sinks; an optional per-site historian: config block lets the RCA copilot pull the 2h pre-incident window as one more cited evidence class (strictly additive — without the config, RCA output is byte-identical, test-proven).
  • Legacy PLC program explainer (plc_program_outline/xref/section, CLI iaiops program …) — structural extraction over exported program files (Siemens SCL/ST .scl/.st, AWL/STL .awl, Rockwell Studio 5000 .L5X — never a live PLC upload); every element carries source_file + line (rung for L5X) so the explaining agent must cite real locations. XXE-hardened, ≤5 MB, extension allowlist.
  • ISA-18.2 alarm flood deep-dive (alarm_flood_analysis / alarm_rationalization_worksheet, CLI iaiops diag alarm-flood|alarm-worksheet) — flood episodes (≥10 alarms/10 min), chattering, stale/standing (>24h), percent-time-in-flood vs target, and a CSV-exportable rationalization worksheet; over injected events or a live OPC-UA active-condition scan.
  • Open-format export + metrics bridgeiaiops export csv|sqlite|parquet (from the local SQLite sink; Parquet via iaiops[export]) / MCP export_data; iaiops metrics serve --port 9184 exposes Prometheus /metrics (latest tag values + counters, binds 127.0.0.1 by default) — Grafana recipe in docs/GRAFANA.md.
  • Compliance deliverablesiaiops compliance report (等保 2.0 L2/L3 status + IEC 62443 FR1–6 crosswalk + honest gap list, md/html) and iaiops compliance evidence (audit-evidence zip with hash-chain verification + manifest); MCP compliance_report / compliance_evidence_bundle. Onboarding aids, 非认证.

Cross-protocol brain & editions — 0.11/0.12 additions (all read-only)

  • Downtime triage copilot (downtime_triage) — composes alarm cascade + RCA verdict + PdM precursors into one triage and cross-checks whether the first-out alarm agrees with the diagnosed cause; advisory, cite-first (builds on the earlier alarm_cascade first-out reconstruction and pdm_forecast time-to-threshold early-warning).
  • Legacy-PLC maintainability (plc_program_visibility) — a risk/maintainability read over an exported ST/AWL/L5X program (size, block count, xref density, undocumented sections), never a live upload — pairs with the plc_program_outline/xref/section explainer.
  • Per-edition tool modules (EDITION_MODULES in mcp_server/profiles.py) — a named edition can carry its own @mcp.tool group that loads only when that edition is selected — never for a bare protocol key and never in the always-on brain, so edition-specific tools stay off other surfaces

评论

加载中…

同类推荐