Governed, vendor-neutral OT data tap + intelligent troubleshooting for AI agents (OPC-UA / Modbus / S7comm / Mitsubishi MC / MTConnect / MQTT-Sparkplug / EtherNet-IP) with a built-in governance harness (audit, budget, risk tiers, MOC) plus OEE, downtime, and asset-inventory analytics
Project description
OT-AIops
Governed, vendor-neutral industrial data tap + intelligent troubleshooting for AI agents — across OPC-UA (incl. Historical Access), Modbus-TCP, S7comm, Mitsubishi MC, MTConnect, MQTT/Sparkplug B (full decode), and EtherNet/IP (Rockwell/Allen-Bradley Logix) — plus OEE/downtime, active asset-inventory, and change-of-value analytics.
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), ranks unhealthy tags, computes OEE / categorizes downtime, and builds an active asset register. 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.2.0 — validated against an in-process OPC-UA simulator (incl. HDA), mocked Modbus/S7/Mitsubishi/EtherNet-IP(pycomm3) clients, static MTConnect XML fixtures, and synthetic MQTT/Sparkplug B protobuf payloads. NOT tested against live PLCs / SCADA / brokers / Logix controllers. 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 | opcua_read_history |
Historical Access (HDA) | R | low | {supported, count, values[]} |
| 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 (full decode) | R | low | {samples:[{sparkplug, payload:{metrics[]}}], seq_gap_count} |
| MQTT/Sparkplug | sparkplug_decode_payload |
decode raw SpB payload | R | low | {metrics:[{name, alias, datatype, value, is_historical}]} |
| MQTT/Sparkplug | sparkplug_node_list |
node discovery + state | R | low | {nodes:[{group_id, edge_node_id, online, devices}], primary_hosts[]} |
| MQTT/Sparkplug | uns_browse |
topic-tree browse | R | low | {topics[], tree{}} |
| MQTT/Sparkplug | mqtt_publish |
publish/command | W | high/MOC | {published_bytes, applied} |
| EtherNet/IP | eip_controller_info |
Logix controller id | R | low | {controller:{vendor, product_name, revision, serial}} |
| EtherNet/IP | eip_list_tags |
tag discovery | R | low | {tag_count, tags:[{name, data_type, structure}]} |
| EtherNet/IP | eip_read_tag |
read one tag/array | R | low | {tag, value, type, good} |
| EtherNet/IP | eip_read_many |
batch read | R | low | {items:[{tag, value, type}]} |
| EtherNet/IP | eip_write_tag |
write tag | W | high/MOC | {before, written, _undo_id} |
| 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[]} |
| Analytics | oee_compute |
OEE = A×P×Q | R | low | {availability, performance, quality, oee, oee_pct} |
| Analytics | downtime_events |
stoppage detect + categorize | R | low | {event_count, total_downtime_s, by_category, events[]} |
| Analytics | oee_multidim |
OEE machine×part×shift | R | low | {matrix[], worst_performers[], mean_oee} |
| Analytics | asset_inventory |
active fingerprint | R | low | {assets:[{protocol, vendor, model, firmware, reachable}]} |
| Analytics | monitor_changes |
bounded change-of-value | R | low | {change_count, changes:[{value, previous, wall_clock}]} |
| Self | protocols_supported |
capability map | R | low | {protocols[], diagnostics[], analytics[]} |
| Roadmap | ethercat_status |
EtherCAT stub | R | low | {implemented:false, suggested_dependency} |
51 tools = 47 read + 4 write (MOC). The 47 reads = 36 protocol-read · 4 diagnostics · 5 analytics · 1 self · 1 roadmap stub. Run protocols_supported() (or ot-aiops protocols) for the live map.
Per-protocol reference
OPC-UA
- Versions/variants: binary
opc.tcp://viaasyncua(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 →decodehint (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 nativelibsnap7). 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:
pymcprotocol— MC 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 boundedcount=samples.
MQTT / Sparkplug B / UNS
- Versions/variants:
paho-mqtt— MQTT 3.1.1 & 5. Sparkplug B topic conventionspBv1.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.protogenerated module (depends only onprotobuf). 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 theis_historical/is_nullflags. 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 flagsseqgaps / out-of-order. Primary-host awareness:STATE/<host_id>topics surface insparkplug_node_list.sparkplug_decode_payloaddecodes 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 published command has no automatic 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_inforeads the controller identity. - Connection params:
host,slot(0 for CompactLogix; the CPU slot for a ControlLogix chassis),port(44818).protocol: ethernetip(aliaseip). - 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 — roadmap stub
ethercat_statusreturns a clear "not implemented" + roadmap. Needs a master stack (pysoem/SOEM) + a dedicated NIC + slave devices.
OEE / downtime analytics (cross-protocol, read-only)
oee_compute— OEE = Availability × Performance × Quality from production inputs (planned time, run time, ideal cycle, total/good counts). Each factor is reported raw + clamped to [0,1]; acappedperformance >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_snapshotsurfaces 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 (S7s7_cpu_info, EtherNet/IPeip_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 (asyncuaread_raw_history), bounded bymax_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 bothduration_s(≤120) andmax_changes(≤500). Read-only.
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
- name: cell5
protocol: ethernetip # alias: eip
host: 10.0.0.9
slot: 0 # 0 for CompactLogix; CPU slot for ControlLogix
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
asyncuademo server (the test suite runs a real in-process one). - Modbus — ModbusPal or a
pymodbusserver 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
mosquittobroker (+ a Sparkplug edge for SpB topics). - Mitsubishi MC — GX Simulator / an MC 3E server sim.
- EtherNet/IP — a pycomm3-compatible CIP/Logix simulator (or a spare CompactLogix).
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 eip tags -e cell5 # Logix tag discovery
ot-aiops eip read "Conveyor.Speed" -e cell5
ot-aiops opcua history "ns=2;i=5" -e line1 --start 2026-06-28T08:00:00Z # HDA
ot-aiops opcua monitor "ns=2;i=5" -e line1 --duration-s 20 --deadband 0.5 # CoV
ot-aiops diag dataflow -e line1 --ref "ns=2;i=5" --freshness-s 30
ot-aiops analytics oee 28800 25200 2.0 12000 11800 # OEE = A×P×Q
ot-aiops analytics asset -e press1 -e cell5 # active asset register
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
ot-aiops eip write-tag Setpoint 42 -e cell5 --apply # Logix tag write (double-confirm)
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" }
eip_read_tag:
{ "tag": "Conveyor.Speed", "endpoint": "cell5" }
{ "endpoint": "cell5", "tag": "Conveyor.Speed", "value": 1500.0, "type": "REAL",
"error": "", "good": true }
eip_write_tag (dry-run):
{ "tag": "Setpoint", "value": 42, "endpoint": "cell5" }
{ "endpoint": "cell5", "tag": "Setpoint", "dry_run": true, "before": 7,
"would_write": 42, "note": "Dry run — nothing written. Re-run with dry_run=false AND a recorded approver…" }
sparkplug_decode_payload (full SpB metric decode):
{ "payload": "CAESBwoDYWJjEAE=", "encoding": "base64" }
{ "encoding": "sparkplug_b", "seq": 0, "metric_count": 2, "historical_count": 0,
"metrics": [ {"name": "Temperature", "alias": 1, "datatype": "Double", "value": 21.5,
"is_historical": false, "is_null": false} ] }
oee_compute:
{ "planned_time_s": 28800, "run_time_s": 25200, "ideal_cycle_time_s": 2.0,
"total_count": 12000, "good_count": 11800 }
{ "availability": {"raw": 0.875, "value": 0.875, "capped": false},
"performance": {"value": 0.952381}, "quality": {"value": 0.983333},
"oee": 0.819444, "oee_pct": 81.94 }
asset_inventory (active fingerprint):
{ "endpoints": ["press1", "cell5"] }
{ "asset_count": 2, "reachable_count": 2, "method": "active_fingerprint",
"assets": [ {"endpoint": "press1", "protocol": "s7", "vendor": "Siemens/compatible",
"model": "CPU 1511-1 PN", "firmware": "2.8", "reachable": true,
"last_seen": "2026-06-28T10:00:00+00:00"} ] }
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. 47 of 51 tools are read-only. The 4 write/command tools (
s7_write_db,mc_write_words,mqtt_publish,eip_write_tag) 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 PLC-5 / SLC-500 (PCCC) and Micro800 support (Logix tags are done in 0.2.0).
- Passive asset discovery (SPAN/tap, no connections) alongside today's active fingerprint.
- EtherCAT read-only PDO/SDO via an optional
pysoemextra. - OPC-UA certificate security + real Alarms & Conditions subscriptions.
- MTConnect streaming long-poll; Sparkplug B DataSet/Template deep expansion.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ot_aiops-0.2.0.tar.gz.
File metadata
- Download URL: ot_aiops-0.2.0.tar.gz
- Upload date:
- Size: 135.5 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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
36ab898a20c84acfa4bfc76c631a98653b01dcf269a5d05dfdf1b673ebcceea7
|
|
| MD5 |
5b61455d0d2865c1fa2629e837183dcd
|
|
| BLAKE2b-256 |
a2d2b0f38e2888fc06b046062d5081e4fa7d4ee2df081d5134e7abb77e47ae88
|
File details
Details for the file ot_aiops-0.2.0-py3-none-any.whl.
File metadata
- Download URL: ot_aiops-0.2.0-py3-none-any.whl
- Upload date:
- Size: 145.5 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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1ace2040db5072209ee901035f6b47af6e0b405f72ef461e3ec08dbf9dfc1760
|
|
| MD5 |
0879011e7dfcf7b93f9ddfeb6b0ada89
|
|
| BLAKE2b-256 |
beeb1510a499d7d99310deb0a69810c3b37c7b5aef98205ab33090c7220a073b
|