Skip to main content

Thin Python wrapper for the rust-ethernet-ip native library

Project description

Python Wrapper

This package is the current thin Python wrapper for the rust-ethernet-ip native library.

Current scope:

  • thin bindings over the existing Rust FFI boundary
  • Pythonic client lifecycle
  • optional route-path connection support for routed ControlLogix targets
  • generic read/write and batch operations

It is intentionally light and keeps Rust as the protocol and performance core.

If you are integrating this into a project, also read:

Local Development

Build the native library first from the repo root. The Python wrapper requires the FFI exports, so include the ffi feature:

cargo build --features ffi

Run the lightweight Python tests from the repo root:

PYTHONPATH=python python3 -m unittest discover -s python/tests

Run the optional simulator-backed integration tests by setting SIM_PLC_ADDRESS to a reachable deterministic simulator instance:

SIM_PLC_ADDRESS=127.0.0.1:44818 PYTHONPATH=python python3 -m unittest discover -s python/tests

Or ask the Python tests to launch the in-repo simulator example automatically:

RUST_ETHERNET_IP_START_SIM=1 PYTHONPATH=python python3 -m unittest discover -s python/tests

The auto-launch path prefers a prebuilt simulator binary at target/debug/examples/python_test_simulator (or .exe on Windows), then falls back to building it. To prebuild both the native FFI library and simulator:

cargo build --features ffi --example python_test_simulator

You can also launch the simulator example directly and point tests or examples at it:

cargo run --features ffi --quiet --example python_test_simulator

Load the package directly from the repo during development:

PYTHONPATH=python python3

If the native library is not in a default repo build output location, set:

export RUST_ETHERNET_IP_NATIVE_LIB=/absolute/path/to/librust_ethernet_ip.dylib

On Windows, point that variable to rust_ethernet_ip.dll.

Current MVP Surface

  • Client(address, route_path=None, auto_connect=True)
  • connect()
  • disconnect()
  • read_tag(name)
  • write_tag(name, value, value_type=None)
  • read_tags(names)
  • write_tags(items)
  • check_health()
  • get_diagnostics_snapshot(detailed=False)

Python float values default to PLC REAL in the wrapper.

If you need LREAL, pass it explicitly with value_type="LREAL".

Diagnostics snapshots are exposed as thin Python dataclasses with nested metrics sections.

For routed ControlLogix access, pass route_path=RoutePath(slots=[cpu_slot]).

On validated ControlLogix hardware, write_tags(...) currently executes writes sequentially in the Python wrapper so per-tag success and error reporting stays accurate on live PLCs.

Examples

  • python/examples/read_single_tag.py
  • python/examples/read_batch_tags.py
  • python/examples/log_tags_to_csv.py
  • python/examples/log_tags_to_sqlite.py
  • python/examples/pandas_dataframe_example.py
  • python/examples/fastapi_service_example.py
  • python/examples/collector_service.py
  • python/examples/mqtt_publisher_example.py

Optional example dependencies:

  • analytics examples: pip install '.[analytics]'
  • API examples: pip install '.[api]'
  • MQTT example: pip install '.[mqtt]'

Collector service example:

PYTHONPATH=python python3 python/examples/collector_service.py \
  --config python/examples/collector_config.example.json \
  --once

The collector uses batch reads and writes timestamped rows to either CSV or SQLite based on the config file. Set RUST_ETHERNET_IP_PLC_ADDRESS to override the PLC address from the config file. Set RUST_ETHERNET_IP_PLC_SLOT to inject a simple slot-only route path for routed ControlLogix targets.

MQTT publisher example:

PYTHONPATH=python python3 python/examples/mqtt_publisher_example.py \
  --config python/examples/mqtt_publisher_config.example.json \
  --once

The MQTT example publishes normalized batch snapshots to a broker topic shaped like factory/{site}/plc/{plc_name}/snapshot. Set RUST_ETHERNET_IP_MQTT_HOST to override the broker host from the config file. Set RUST_ETHERNET_IP_PLC_SLOT to inject a simple slot-only route path for routed ControlLogix targets.

The FastAPI example also supports:

  • RUST_ETHERNET_IP_PLC_ADDRESS
  • RUST_ETHERNET_IP_PLC_SLOT
  • RUST_ETHERNET_IP_API_HOST
  • RUST_ETHERNET_IP_API_PORT

Docker example stack:

docker compose -f docker/python-stack/docker-compose.yml up --build

Scope Guardrail

This package is an enablement layer for Python users.

The Rust library remains the source of truth for:

  • EtherNet/IP behavior
  • correctness
  • performance
  • protocol semantics

Current Validation Status

  • pure-Python unit tests run with the standard library unittest
  • integration tests exist for simulator-backed connect/read/write/batch flows
  • simulator-backed tests are skipped automatically when SIM_PLC_ADDRESS is not set
  • integration tests can auto-launch the in-repo simulator with RUST_ETHERNET_IP_START_SIM=1
  • simulator-backed batch coverage includes mixed DINT, REAL, BOOL, and STRING flows

Support and Collaboration

For bugs and integration questions:

The project is also open to:

  • priority issue handling
  • priority feature sponsorship
  • integration support for real deployments
  • companies willing to provide specific PLC hardware for validation

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

rust_ethernet_ip-1.1.0.tar.gz (20.7 kB view details)

Uploaded Source

Built Distributions

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

rust_ethernet_ip-1.1.0-py3-none-win_amd64.whl (710.2 kB view details)

Uploaded Python 3Windows x86-64

rust_ethernet_ip-1.1.0-py3-none-manylinux_2_28_x86_64.whl (920.0 kB view details)

Uploaded Python 3manylinux: glibc 2.28+ x86-64

rust_ethernet_ip-1.1.0-py3-none-macosx_11_0_universal2.whl (773.3 kB view details)

Uploaded Python 3macOS 11.0+ universal2 (ARM64, x86-64)

File details

Details for the file rust_ethernet_ip-1.1.0.tar.gz.

File metadata

  • Download URL: rust_ethernet_ip-1.1.0.tar.gz
  • Upload date:
  • Size: 20.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for rust_ethernet_ip-1.1.0.tar.gz
Algorithm Hash digest
SHA256 dda2eeb009295bf6b2835655ea829cfb8d73eadff5500d97902d630d0ccbfb09
MD5 df3ba721e28f689b1231f562ef184f74
BLAKE2b-256 d2e63ce0f4499eb2ae45abc2546e89a6d827764a50078c611adc2a1998f10648

See more details on using hashes here.

File details

Details for the file rust_ethernet_ip-1.1.0-py3-none-win_amd64.whl.

File metadata

File hashes

Hashes for rust_ethernet_ip-1.1.0-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 3957060a4c490a1cdef9d8d5fcd89c559bfcf6956f0adb2b0a295017c9b9b82c
MD5 1966a528e4a43a45d665380cfbe080e1
BLAKE2b-256 ad634af9c61fc11a122e31bdb13e35ff062b759a3bf1e58950e3d8a073025d6d

See more details on using hashes here.

File details

Details for the file rust_ethernet_ip-1.1.0-py3-none-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for rust_ethernet_ip-1.1.0-py3-none-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 2e2f61bfc282c4a1062190fba3e6863b2c888ebcf1bab2820d343cc99f224836
MD5 c84e4db3b9d555f5a9a4259b43454722
BLAKE2b-256 f390d003c142cfc2594a1989b6cf07de8e96acd85ea236e002dba7b00e4338c6

See more details on using hashes here.

File details

Details for the file rust_ethernet_ip-1.1.0-py3-none-macosx_11_0_universal2.whl.

File metadata

File hashes

Hashes for rust_ethernet_ip-1.1.0-py3-none-macosx_11_0_universal2.whl
Algorithm Hash digest
SHA256 d9f8524c1ebd6f5acaa8d358bf701077d196dd99866c02b83823a68c578c4628
MD5 96540208103747e4f5de6b1f282d3428
BLAKE2b-256 349b8e3c91250d28ae922c9c464bdfd967de6711e21ca3f5e4cf6a29953cd370

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