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.2.0.tar.gz (21.2 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.2.0-py3-none-win_amd64.whl (730.3 kB view details)

Uploaded Python 3Windows x86-64

rust_ethernet_ip-1.2.0-py3-none-manylinux_2_28_x86_64.whl (929.1 kB view details)

Uploaded Python 3manylinux: glibc 2.28+ x86-64

rust_ethernet_ip-1.2.0-py3-none-macosx_11_0_universal2.whl (780.5 kB view details)

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

File details

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

File metadata

  • Download URL: rust_ethernet_ip-1.2.0.tar.gz
  • Upload date:
  • Size: 21.2 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.2.0.tar.gz
Algorithm Hash digest
SHA256 ff014cf40339f82176f5f14717b7d9dd479fb20923e50b52d27153597fc14f34
MD5 a7dc8f9843e9613db8c571e5bc0f137c
BLAKE2b-256 f7905976b0847a42f4ec2de1de324c6a0788650cb13ad55dfbc1c3706fcea79f

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for rust_ethernet_ip-1.2.0-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 ef074371d867e528ceef7f746f779239fbed7d28db7f6e8d17a61a91c52145d8
MD5 51b5791404485c2bcb054614da25e2ec
BLAKE2b-256 5877086f66f08454ff3699fca00648b17a63ab822fb980dc66ea93668df23b5b

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for rust_ethernet_ip-1.2.0-py3-none-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 07e6bec95fcdb20c1da82356c82fa62a0f7d87ffe3813b1048010023ad56b728
MD5 63bb2fbcc072bb28b134af930f93b78c
BLAKE2b-256 75f3448a800116c3a36a153b79873175396a69c2ca7757a6f75d27d1a39fa52a

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for rust_ethernet_ip-1.2.0-py3-none-macosx_11_0_universal2.whl
Algorithm Hash digest
SHA256 77fae20bcee759aca6fa2d83ae3755229447740bd88b36a632b3042fcdfa5054
MD5 26cc66eb822875d1b187160ee80dcca0
BLAKE2b-256 d03bb367ad0730c839cb68237cde9f9bd5fa8bff8d0ba67c49789b2c8917e5b3

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